1
votes

I have an asp.net MVC 4 Web API that was created in VS2010. It is currently hosted on a Windows Server 2003 box running IIS 6.0. The API works great when I navigate to it using Google Chrome from my machine (on the same network as the server). The issue I am having is when I try to consume the API from a VS2013 C# console app. I am getting the following response:

{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:

{ Server: Microsoft-IIS/6.0 WWW-Authenticate: Negotiate WWW-Authenticate: NTLM X-Powered-By: ASP.NET Date: Mon, 04 Apr 2016 16:09:50 GMT Content-Length: 1539 Content-Type: text/html }}

Here is the code for the console app:

static void Main(string[] args) {
    RunAsync().Wait();
    Console.ReadLine();
}

static async Task RunAsync() {
    using (var client = new HttpClient()) {
        client.BaseAddress = new Uri("http://server/website/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await client.GetAsync("api/rateshop/1000/03/90210/");
        if (response.IsSuccessStatusCode) {
            RatingResultModel rateResults = await response.Content.ReadAsAsync<RatingResultModel>();
            foreach (var rate in rateResults.Rates) {
                Console.WriteLine("{0}\t${1}", rate.Service, rate.Rate);
            }
        } else {
            Console.WriteLine("{0}\n{1}", response.StatusCode, response.RequestMessage);
        }
    }
}

My actual WebAPI has [AllowAnonymous] above the ApiController.

The IIS 6.0 server has Anonymous Authentication enabled, and the current user is set to the server administrator, and I provided full control to the website directory for the administrator. Integrated Windows Authentication is also enabled.

So far everything I have searched for is either documentation on how to "Return a 401 status code" instead of what to do when a 401 status code is returned, or it is documentation on how to add authentication to a Web API instead of how to remove it. There seems to be very little on how to handle a Web API in IIS 6.0. As far as I can tell, anonymous authentication is enabled.

I have already tried this stackoverflow answer and I've followed MSDN's article on adding anonymous access to IIS 6.0. I don't believe I will need authentication or authorization security for this Web API since it is going to be used on a local network.

Given that the API works when I consume it with Google Chrome from my machine, what might be causing my issue with trying to use a console app to consume the Web API?

1
You can try adding the following in your web.config file: <security> <authorization> <add accessType="Allow" users="*" /> </authorization> </security>Hackerman
Thank you @Hackerman, I have tried that as well with no luck.mighty_mite
can you do something like using (var clientHandler = new HttpClientHandler() { UseDefaultCredentials = true }) { using (var client = new HttpClient(clientHandler)) { } } and try? seems you have windows and anonymous both enabled so sending credentials with the request would be a good idea..Nilesh
@Nilesh that totally works, and makes sense! Thank you!mighty_mite
Windows Server 2003 has been dead for a few months already. Make sure you switch as soon as possible.Lex Li

1 Answers

0
votes

Thanks to @Nilesh for the answer.

Wrapping my RunAsync method in a using (var clientHandler = new HttpClientHandler() {UseDefaultCredentials = true}) did the trick.

Full solution:

using (var clientHandler = new HttpClientHandler()) {
    clientHandler.UseDefaultCredentials = true;

    using (var client = new HttpClient(clientHandler)) {
        client.BaseAddress = new Uri("http://server/website/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await client.GetAsync("api/rateshop/1000/03/90210/");
        if (response.IsSuccessStatusCode) {
            RatingResultModel rateResults = await response.Content.ReadAsAsync<RatingResultModel>();
            foreach (var rate in rateResults.Rates) {
                Console.WriteLine("{0}\t${1}", rate.Service, rate.Rate);
            }
        } else {
            Console.WriteLine("{0}\n{1}", response.StatusCode, response.RequestMessage);
        }
    }
}