Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebException on HTTP request while debugging

Tags:

I have a ASP.NET project which involves sending HTTP requests via the Web-API Framework. The following exception is only raised when debugging:

The server committed a protocol violation. Section=ResponseStatusLine

The project runs perfectly if I "Start Without Debugging".

How should I resolve this exception?

Any help is appreciated!


Update

The problem seems related to the ASP.NET MVC Identity Framework.

To access other Web-API methods, the client application has to first POST a login request (The login request does not need to be secure yet, and so I am sending the username and password strings directly to the Web-API POST method). If I comment out the login request, no more exception is raised.

Below are the relevant code snippets:

The Post method:

UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
AccountAccess ac = new AccountAccess();

public async Task<HttpResponseMessage> Post()
{
    string result = await Request.Content.ReadAsStringAsync();
    LoginMessage msg = JsonConvert.DeserializeObject<LoginMessage>(result);
    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
    var user = UserManager.Find(msg.username, msg.password);
    if (user == null)
        return response;
    if (user.Roles == null)
        return response;
    var role = from r in user.Roles where (r.RoleId == "1" || r.RoleId == "2") select r;
    if (role.Count() == 0)
    {
        return response;
    }
    bool task = await ac.LoginAsync(msg.username, msg.password);
    response.Content = new StringContent(task.ToString());
    return response;
} 

The Account Access class (simulating the default AccountController in MVC template):

public class AccountAccess
{
    public static bool success = false;
    public AccountAccess()
        : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
    {
    }

    public AccountAccess(UserManager<ApplicationUser> userManager)
    {
        UserManager = userManager;
    }

    public UserManager<ApplicationUser> UserManager { get; private set; }

    public async Task<bool> LoginAsync(string username, string password)
    {
        var user = await UserManager.FindAsync(username, password);
        if (user != null)
        {
             await SignInAsync(user, isPersistent: false);
             return true;
        }
        else
        {
            return false;
        }
    }
    ~AccountAccess()
    {
        if (UserManager != null)
        {
            UserManager.Dispose();
            UserManager = null;
        }
    }

    private IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.Current.GetOwinContext().Authentication;
        }
    }

    private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    }
}

Below are the relevant code snippets:

In client application:

public static async Task<List<T>> getItemAsync<T>(string urlAction)
{
    message = new HttpRequestMessage();
    message.Method = HttpMethod.Get;
    message.RequestUri = new Uri(urlBase + urlAction);
    HttpResponseMessage response = await client.SendAsync(message);
    string result = await response.Content.ReadAsStringAsync();
    List<T> msgs = JsonConvert.DeserializeObject<List<T>>(result);
    return msgs;
}

In Web-API controller:

public HttpResponseMessage Get(string id)
{
    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
    if (id == "ItemA")
    {
        List<ItemAMessage> msgs = new List<ItemAMessage>();

        // some code...

        response.Content = new StringContent(JsonConvert.SerializeObject(msgs));
    }
    else if (id == "ItemB")
    {
         List<ItemBMessage> msgs = new List<ItemBMessage>();

        // some code...

        response.Content = new StringContent(JsonConvert.SerializeObject(msgs));
    }
    return response;
}

Some observations I have:

  1. I thought that I may need to send the request asynchronously (with the async-await syntax), but the exception still persists that way.
  2. If I step through the code, the request does enter the HTTP method, but the code breaks at random line (Why?!) before returning the response, so I assume no response is being sent back.
  3. I have tried the following solutions, as suggested in answers to similar questions, none of which works for me:
    • Setting useUnsafeHeaderParsing to true
    • Adding the header Keep-Alive: false
    • Changing the port setting of Skype (I don't have Skype, and port 80 and 443 are not occupied)

Additional information, in case they matter:

  • Mac OS running Windows 8.1 with VMware Fusion
  • Visual Studio 2013
  • .NET Framework 4.5
  • IIS Express Server

Update 2

The exception is resolved, but I am unsure of which modification did the trick. AFAIK, either one or both of the following fixed it:

  • I have a checkConnection() method, which basically sends a GET request and return true on success. I added await to the HttpClient.SendAsync() method and enforced async all the way up.
  • I retracted all code in the MainWindow constructor, except for the InitializeComponent() method, into the Window Initialized event handler.

Any idea?

Below are relevant code to the modifications illustrated above:

the checkConnectionAsync method:

public static async Task<bool> checkConnectionAsync()
{
    message = new HttpRequestMessage();
    message.Method = HttpMethod.Get;
    message.RequestUri = new Uri(urlBase);
    try
    {
        HttpResponseMessage response = await client.SendAsync(message);
        return (response.IsSuccessStatusCode);
    }
    catch (AggregateException)
    {
        return false;
    }
}

Window Initialized event handler (retracted from the MainWindow constructor):

private async void Window_Initialized(object sender, EventArgs e)
{
    if (await checkConnectionAsync())
    {
        await loggingIn();
        getItemA();
        getItemB();
    }
    else
    {
        logMsg.Content = "Connection Lost. Restart GUI and try again.";
    }
}

Update 3

Although this may be a little off-topic, I'd like to add a side note in case anyone else falls into this – I have been using the wrong authentication approach for Web-API to start with. The Web-API project template already has a built-in Identity framework, and I somehow "replaced" it with a rather simple yet broken approach...

This video is a nice tutorial to start with.

This article provides a more comprehensive explanation.

like image 611
Thomas Hsieh Avatar asked Aug 27 '15 20:08

Thomas Hsieh


People also ask

How do I enable debugging in web config?

In the Web. config file, locate the compilation element. Debugging is enabled when the debug attribute in the compilation element is set to true. Change the debug attribute to false to disable debugging for that application.

How do I run a webservice in debug mode?

Running the Web Service in Debug Mode To run the web service: In the navigator, right-click the web service container, and choose Debug. The embedded OC4J server is started in debug mode, and the web service is deployed to it. The results are displayed in the log window.


1 Answers

In the Client Application you are not awaiting task. Accessing Result without awaiting may cause unpredictable errors. If it only fails during Debug mode, I can't say for sure, but it certainly isn't the same program (extra checks added, optimizations generally not enabled). Regardless of when Debugging is active, if you have a code error, you should fix that and it should work in either modes.

So either make that function async and call the task with the await modifier, or call task.WaitAndUnwrapException() on the task so it will block synchronously until the result is returned from the server.

like image 183
Kind Contributor Avatar answered Oct 22 '22 15:10

Kind Contributor