Search code examples
c#returnusing

Return statement inside using statemtn cause error "Not all code path return value"


This code is look fine for me, I suppose nothing wrong to use return statement inside using statement, but compiler said that not all code path return value. How should I fix this to be able return string result?

public static string CallWebService(string an, string xmlcommand)
        {
            //test
            //Dim _url = "http://testapi.interface-xml.com/appservices/ws/FrontendService"
            //live
            dynamic _url = "http://212.170.239.18/appservices/ws/FrontendService";
            try
            {
                string soapResult = null;
                XmlDocument soapEnvelopeXml = CreateSoapEnvelope(xmlcommand);
                HttpWebRequest webRequest = CreateWebRequest(_url, an);
                webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
                InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
                IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
                asyncResult.AsyncWaitHandle.WaitOne();
                using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
                {
                    using (BufferedStream bs = new BufferedStream(webResponse.GetResponseStream()))
                    {
                        using (GZipStream gz = new GZipStream(bs, CompressionMode.Decompress))
                        {
                            using (StreamReader rd = new StreamReader(gz))
                            {
                                if (an == "HotelValuedAvailRQ")
                                {
                                    soapResult = rd.ReadLine();
                                }
                                else
                                {
                                    soapResult = rd.ReadToEnd();
                                }
                                return soapResult; //This is what I want to return
                            }
                        }
                    }
                }

            }
            catch (TimeoutException ex)
            {
                StringBuilder s = new StringBuilder(2000);
                s.AppendFormat("<b>К сожалению превышено время ожидания.</b>: {0} <br /><b>Источник</b>: {1}<br /><a href='javascript:history.back();'>Вернуться</a>", ex.Message, ex.InnerException);
                HttpContext.Current.Session["bug"] = s.ToString();
                HttpContext.Current.Response.Redirect("../errors/error.aspx");
            }
        }

Solution

  • The problem isn't your using statement, but your try statement: excecution could abort anywhere in your try block before it gets to return, then code would enter your catch(TimeoutException ex) handler, but you don't have a return statement in there.

    I see your code seems to be part of a web-application, however this looks like a "backend" method that returns content to a consuming method. You should not write to Response from here, instead return null or don't catch the exception and instead let the caller of your CallWebService be responsible for displaying an error message.

    I see you're making a few other mistakes like using dynamic instead of String, this is how I would write your code:

    public static string CallWebService(string an, string xmlcommand)
    {
        String url = @"http://212.170.239.18/appservices/ws/FrontendService";
        try
        {
            String soapResult = null;
            XmlDocument soapEnvelopeXml = CreateSoapEnvelope(xmlcommand);
            HttpWebRequest webRequest = CreateWebRequest(_url, an);
            webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
            InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
            using(HttpWebResponse response = webRequest.GetResponse())
            using (Stream s = webResponse.GetResponseStream())
            using (StreamReader rd = new StreamReader(gz))
            {
                if (an == "HotelValuedAvailRQ")
                {
                    soapResult = rd.ReadLine();
                }
                else
                {
                    soapResult = rd.ReadToEnd();
                }
                return soapResult;
            }
        }
        catch (WebException)
        { 
            return null;
        }
        catch (TimeoutException)
        {
            return null;
        }
    }
    
    • You were using dynamic incorrectly. dynamic is not equivalent to VB's Dim statement.
    • You were using the async methods of HttpWebRequest but blocking, so you might as well just use the blocking methods (GetResponse)
    • You shouldn't wrap the Response's stream in a BufferedStream, just use it directly.
    • You can combine using blocks together.
    • You don't need to perform GZip decompression yourself, HttpWebResponse does this automatically: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.automaticdecompression.aspx
    • I don't think it's a good idea to control the ASP.NET HTTP response from a backend method as it leaves the consumer of CallWebService in an unknown state, instead the consumer should check to see if CallWebService returns null and if so, render the error message.

    Note that in both catch blocks, you might want to log the exceptions because their details are being swallowed. They may indicate a downed service or other problem.