189

I'm working with ASP.NET MVC 4 WebApi and am having a lot of fun with it running it on my local computer on IIS Express. I've configured IIS Express to serve remote machines too, and so other's in my company are using my computer as our webserver.

After deciding this was a less-than-optimal solution, we decided to put the WebApi on a remote server after installing .NET 4.5. When I use fiddler and sent a POST to a controller on my local machine it returns the correct response, yet when I change the domain to the webserver running IIS7 the same POST returns a cryptic

{"message":"an error has occurred"}

message. Anyone have any idea what could be going on?

Sameer Alibhai
  • 3,092
  • 4
  • 36
  • 36
nsg
  • 10,510
  • 4
  • 21
  • 32
  • 2
    What's the HTTP status code on the error response? If it's 500 it's very likely the web site/application config is invalid for the remote machine with IIS 7. Create a simple HTML file on the remote machine, browse it on the remote machine if possible to make sure it can be viewed and then try to hit it from your machine to see if it is successful or not. – Sixto Saez Oct 22 '12 at 21:34
  • It is a 500-error. Thanks for the suggestion, but the default index.html page that the WebApi provides works. Also should add that some of the API webservices work and others don't, whereas all of them work on my local machine. – nsg Oct 22 '12 at 23:16
  • 2
    You'll need to enable [IIS request tracing](http://www.iis.net/learn/troubleshoot/using-failed-request-tracing/troubleshooting-failed-requests-using-tracing-in-iis) to get more specifics when you see a 500 error. A 500 error usually occurs before the Web API routing kicks but I guess its possible to trigger it by something your code is doing. Look at the IIS trace logging and see if that offers any clues. – Sixto Saez Oct 23 '12 at 12:10
  • 1
    You might be able to get the server to give you more verbose error information in its response by initiating the request from a browser on the server machine itself (e.g. using a Remote Desktop session). – Jon Schneider Feb 16 '16 at 20:32

9 Answers9

297

The problem was a missing dependency that wasn't on the server but was on my local machine. In our case, it was a Devart.Data.Linq dll.

To get to that answer, I turned on IIS tracing for 500 errors. That gave a little bit of information, but the really helpful thing was in the web.config setting the <system.web><customErrors mode="Off"/></system.web> This pointed to a missing dynamically-loaded dependency. After adding this dependency and telling it to be copied locally, the server started working.

Liam Laverty
  • 152
  • 2
  • 9
nsg
  • 10,510
  • 4
  • 21
  • 32
  • 41
    Looks like WebAPI will substitute {"message":"an error has occurred"} for the real response whenever the HTTP response code is 500 and custom errors are on. Thanks for the pointer. – Paul Suart Jul 04 '13 at 05:08
  • 5
    Great suggestion about setting customErrors mode. I'm suprised changing that had an impact on the output of these kind of errors. – Dewi Rees Jan 28 '14 at 13:00
  • 1
    you can also set it to `mode="RemoteOnly"` and if you run the page on a webbrowser on the server you'll also see the errors without compromising security if the rest of the site is externally accessible – Simon_Weaver Jul 17 '14 at 08:55
  • 1
    Any suggestions on how to get this kind of error detail when changing that setting isn't possible (e.g. errors are disabled at the machine level because the API part is hosted on a PCI-compatible server)? I tried setting up Elmah, but it's not logging anything unfortunately. – Scott Salyer Aug 17 '15 at 16:46
  • This is the best approach, gives enough info on such a generic method. – DanielV Sep 19 '16 at 12:40
  • Lifesaver. Great Option that helped me finding a wrong Databasename in my connectionString. Thank you :) – Marty_in_a_Box Aug 04 '17 at 09:52
  • Thanks a lot.Tried to add `` doesnt show the detailed error. – sky91 Apr 16 '20 at 03:51
104

Basically:

Use IncludeErrorDetailPolicy instead if CustomErrors doesn't solve it for you (e.g. if you're ASP.NET stack is >2012):

GlobalConfiguration.Configuration.IncludeErrorDetailPolicy 
= IncludeErrorDetailPolicy.Always;

Note: Be careful returning detailed error info can reveal sensitive information to 'hackers'. See Simon's comment on this answer below.

TL;DR version

For me CustomErrors didn't really help. It was already set to Off, but I still only got a measly an error has occurred message. I guess the accepted answer is from 3 years ago which is a long time in the web word nowadays. I'm using Web API 2 and ASP.NET 5 (MVC 5) and Microsoft has moved away from an IIS-only strategy, while CustomErrors is old skool IIS ;).

Anyway, I had an issue with products that I didn't have locally. And then found I couldn't see the errors in Chrome's Network tab like I could on my dev machine. In the end, I managed to solve it by installing Chrome on my production server and then browsing to the app there on the server itself (e.g. on 'localhost'). Then more detailed errors appeared with stack traces and all.

Only afterward did I find this article from Jimmy Bogard (Note: Jimmy is mr. AutoMapper!). The funny thing is that his article is also from 2012, but in it, he already explains that CustomErrors doesn't help for this anymore, but that you CAN change the 'Error detail' by setting a different IncludeErrorDetailPolicy in the global WebApi configuration (e.g. WebApiConfig.cs):

GlobalConfiguration.Configuration.IncludeErrorDetailPolicy 
= IncludeErrorDetailPolicy.Always;

Luckily he also explains how to set it up that web API (2) DOES listen to your CustomErrors settings. That's a pretty sensible approach, and this allows you to go back to 2012 :P.

Note: The default value is 'LocalOnly', which explains why I was able to solve the problem the way I described, before finding this post. But I understand that not everybody can just remote to production and startup a browser (I know I mostly couldn't until I decided to go freelance AND DevOps).

commadelimited
  • 5,656
  • 6
  • 41
  • 77
Bart
  • 5,065
  • 1
  • 35
  • 43
  • 2
    Now, this works. Thank you! I have some in-memory-integration-owin-kind of tests which fails on the build server, but not locally. With this setting in my startup-class, I may have a chance to figure out why. – Thomas Eyde Jan 05 '16 at 13:52
  • It appears that the customError setting works with WebApi 2 when hosted in IIS through Microsoft.AspNet.WebApi.WebHost. The packages are version 5.2.3, so ASP.NET stack way past 2012. By setting it to Off, the web api switches from generic errors to more detailed, containing the call stack, etc... – tstojecki May 23 '16 at 15:38
  • 4
    Be careful setting this because it can reveal sensitive information to 'hackers'. I'll often do a quick hack something like `if (DateTime.Now < new DateTime(2017, 6, 22)) { .... }` to set an option like this. Then i can test it in production and tomorrow it will magically revert back to normal behavior if I forget to disable it. – Simon_Weaver Jun 21 '17 at 19:35
  • There is a good article here about this too: https://lostechies.com/jimmybogard/2012/04/18/custom-errors-and-error-detail-policy-in-asp-net-web-api/ – santos Jul 27 '21 at 13:03
41

None of the other answers worked for me.

This did: (in Startup.cs)

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();

        WebApiConfig.Register(config);

        // Here: 
        config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
    }
}

(or you can put it in WebApiConfig.cs):

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        // Here: 
        config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
    }
}
samneric
  • 3,038
  • 2
  • 28
  • 31
  • Yes!, This was the only working solution for me on Mono/Linux. – John Doe Mar 28 '18 at 07:03
  • This worked for me on prod for an internally served app on IIS and Windows Server. – Paul Carlton Aug 20 '18 at 19:24
  • config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always; helped me find that i return an instance of a an entity that couldn't be parsed because the context has been disposed **thank you** – Jood jindy Apr 05 '20 at 19:55
17

I always come to this question when I hit an error in the test environment and remember, "I've done this before, but I can do it straight in the web.config without having to modify code and re-deploy to the test environment, but it takes 2 changes... what was it again?"

For future reference

<system.web>
   <customErrors mode="Off"></customErrors>
</system.web>

AND

<system.webServer>
  <httpErrors errorMode="Detailed" existingResponse="PassThrough"></httpErrors>
</system.webServer>
Rick Glos
  • 2,466
  • 2
  • 29
  • 30
14

In case this helps anyone:

I had a similar issue, and following Nates instructions I added:

<system.web>
     <customErrors mode="Off"/>
 </system.web>

This showed me more information about the error:

"ExceptionMessage": "Unable to load the specified metadata resource.", "ExceptionType": "System.Data.Entity.Core.MetadataException", "StackTrace": " at System.Data.Entity.Core.Metadata.Edm.MetadataArtifactLoaderCompositeResource.LoadResources(...

This is when I remembered that I had moved the edmx file to a different location and had forgotten to change the connectionstrings node in the config (connectionsstrings node was placed in a seperate file using "configSource", but that's another story).

Bernard Vander Beken
  • 4,848
  • 5
  • 54
  • 76
hormberg
  • 184
  • 2
  • 8
  • This happened to me when adding OData and AutoMapper to a web api in asp.net - hopefully these keywords help somebody reach this post, and try/catch didn't work in my case so I had to see the raw result – Ekus Apr 30 '19 at 20:18
12

I had a similar problem when posting to the WebAPI endpoint. By turning the CustomErrors=Off, i was able to see the actual error which is one of the dlls was missing.

ctong
  • 185
  • 1
  • 3
0

My swagger XML file was not deployed into \bin:

GlobalConfiguration.Configuration
  .EnableSwagger(c =>
  {
    c.SingleApiVersion("v1", "SwaggerDemoApi");
    c.IncludeXmlComments(string.Format(@"{0}\bin\SwaggerDemoApi.XML", 
                         System.AppDomain.CurrentDomain.BaseDirectory));
    c.DescribeAllEnumsAsStrings();
  })

http://wmpratt.com/swagger-and-asp-net-web-api-part-1/

enter image description here

It had to be set in the Release Configuration as well as in the Debug Configuration.

RaSor
  • 869
  • 10
  • 11
0

If you have <deployment retail="true"/> in your .NET Framework's machine.config, you won't see detailed error messages. Make sure that setting is false, or not present.

Eric H
  • 236
  • 1
  • 3
  • 12
0

So i tried all the suggested solutions to no avail. All i did was to set run the app from the server and it displayed the error in full, this should have worked when i set customErrors mode to false but it didn't. The moment i browsed the API form the server i was able to see the problem.

Prince Tegaton
  • 222
  • 1
  • 4
  • 14