WebAPI 2 Routing/hosting mishaps - c#

I am having a bit of a terrible time getting a WebAPI 2 setup to work. I am trying to place this within an already existing solution containing multiple projects.
The current layout is (with generalized names):
-Server.Project
-Services.Project
Right now, IIS is doing the hosting. There is an application setup in IIS called Application.
So, right now if you go to localhost/Application/service.asmx , everything spins up and does it's thing. The global.asax.cs file and most of the service classes are in Services.Project, even though Server.Project is the software's entry point.
I want to make use of WebAPI's new things.
I've defined a controller (TestAPIController) in Services.Project, and a configuration file with the default mappings (from all of the examples). The Register() function is called from Application_Start(). I've verified that it is at least being called.
If I go to:
localhost/Application/TestAPI/anything ever, it gives me a 404 error.
I tried to use the Route Debugger by installing the package and going to localhost/Application/rd (also tried /Application/TestAPI/rd). Neither work. I get a 404.
This leads me to believe I have something setup wrong so that the WebAPI stuff is not actually spinning up and hosting correctly.
I have tried doing the OWIN startup as well, but it didn't seem to help.
For that, I just added the appropriate startup class stuff to my web.config, and to my Global class in Services.Project.
I've verified that the Configuration() function for Owin is being called as well, but I still cannot hit the paths I've setup.
I think the fact that the entry point is Server.Project, but the controller/routes are defined in Services.Project might be part of the issue.
However, all of the assemblies are placed in the same bin directory. I was lead to believe this should allow everything to be loaded/found.
Am I missing something?
If anything is not clear, sorry. Let me know so I can clear it up.
Thanks.
EDIT:
So, I got a different route debugger to install and cooperate.
(install-package RouteDebugger).
If I hit my main URL: localhost/application
This route debugger launches and shows that no paths were matched, but it ALSO shows the routing paths that I defined but are not found.
...so now I am even more confused. How are they showing up and obviously known about, but are unable to be reached?

If you followed "typical" WebAPI setup tutorials, you would have defined the custom ApiController route to include "/api".
All of your urls should look like:
localhost/Application/api/TestAPI/anything
As an aside, it might be worth it to just spin up a brand new Web API project. Retrofitting an existing project might cause more headaches than it's worth.

Related

Web API returns results but doesn't hit breakpoint even when symbols are correctly loaded

This is the weirdest thing that has ever happened to me so please hear me out.
Symbols are getting loaded properly. So thats not an issue.
API is working and the data is valid.
I've 2 controllers in the same project. One controller's breakpoint is hit when I make a GET request. But the second controller's breakpoint isn't getting hit. However it does return results correctly.
I'm putting a breakpoint at the constructor level (and have tried everywhere else) but not sure what is going wrong.
The code is pretty normal C# MVC web api.
Does anyone know what might cause this behavior?
One trick I like to use is to use Exceptions. First you change some public method in your "bad" Controller to just unconditionally throw some dummy Exception. Then call that method from whatever uses you WebAPI and make sure the Exception is actually thrown. Sometimes something get cached and code is not actually re-compiled or something.
Then attach your debugger and see if it catches the Exception. You might be attaching to a wrong process.
Next modify code to throw and catch that Exception and just log it. The trick here is that VS Debugger has an option to stop even on caught aka "user-handled" exceptions: see configuration here for VS up to 2013 and here for VS 2015+. Then you can see if symbols actualy matches the code.
I had similar issue - try this site out that might help
breakpoint issue
Meanwhile try to force a breakpoint
System.Diagnostics.Debugger.Break();
Does the controller, which works but doesn't hit the breakpoint, output cache whatever it is that is being generated? If it is, the data will be returned by whatever is caching it, and the controller won't be instantiated.
It's not clear whether you are using MVC or WebAPI controllers or what you are returning. However if it's MVC you could look for the [OutputCache()] attribute. You could also keep an eye out for other cache related headers which might be getting added.
Depending on the caching strategy you might be able to circumvent it by adding a random query string value so that it has to create a new cache key. For example:
http://example.com/some/path/1234?cow=moo
try this instead
1.Go to project "Build settings"
2.Search Debug
3.Under Apple Clang - Code Generation check "Optimization Level"
4.Set Debug to None [-OO]
I had the same problem just a moment ago before writing this down... Try going to properties of you webapi and compare if the project url found in the web section is the same as the url specified in your website's webconfig file. As for my problem, the website was pointing to the webapi properly which allows any code changes in the webapi to be read however, the debugger is pointed in the wrong place thus it cannot read any breakpoints you place.

DbConfigurationTypeAttribute in code vs. codeConfigurationType in web.config

We're working on an EF6 application, that uses a custom DbConfiguration class. Up til now, we've been configuring system to use our DbConfiguration, rather than creating a default, by decorating each DbContext class with a DbConfigurationTypeAttribute.
We installed an instance on our QA site, today, and were getting HTTP 500 errors. After turning off CustomErrors, so we could see the detail, we saw:
An instance of 'DbConfigurator' must be set at application start
before using any Entity Framework features or must be registered in
the application's config file.
This confused me, because according to Microsoft, the DbConfigurationTypeAttributes should have worked:
https://msdn.microsoft.com/en-us/data/jj680699#Moving
And they did work, on our Development machines. And I am absolutely certain that each of our DbContext objects is so decorated.
Not knowing what else to do, I added the codeConfigurationType attribute to the entityFramework element in the web.config and everything ran fine.
I then tried removing the DbConfigurationTypeAttributes from the code, thinking that defining this in multiple places was a bad idea. And all my unit tests proceeded to fail - they don't access the web.config. That part, at least, makes sense.
The rest of it, though, confuses me. Why do the DbConfigurationTypeAttributes not work, when running in IIS7?

Self-Hosted Web API - Referenced Controllers Don't Work with "Optimize Code" Option

I have an ASP.NET Web API project hosted in a Windows Service, using OWIN. I'm using a Startup class that configures some things, and am using the IAppBuilder.UseWebApi() option. Everything works perfectly in the debugger and from the command line (I use a command line argument of -e to run in console, or it can run as a Windows Service).
Everything is working great, BUT, when I build in Release mode with the build option enabled for "Optimize Code", my service controllers don't seem to work.
I have my controller in a separate class library, and I'm using this line to probe the controller on application start, as suggested here: Self-hosting WebAPI application referencing controller from different assembly
var controllerType = typeof(MetricsController);
I have a feeling that the Optimize Code option causes the compiler to ignore this line. Does anyone have any insight or ideas about how I can make this work?
Thanks!
After working with this for a bit, I implemented the following approach which the Optimize Code option seems to be happy with.
Class-level member:
private readonly List<Type> _controllers = new List<Type>();
Then in my Startup.Configuration method, I replaced this:
// Hack: This forces a manual probe of the controller assembly
var controllerType = typeof(MyController);
With this:
// Better Hack: This forces a manual probe of the controller assembly
_controllers.Add(typeof(MyController));
What seems to be happening is that the Optimize Code option is stripping out logic that is declared but never used. In this case, I was using the original hack to probe the assembly so the application knows about its existence. Since it was so tightly scoped and the variable controllerType was never used, the compiler ignores it. The new approach is probably just enough of a hint that it may be used that the compiler keeps it.
I tried a reflection-based approach but could not get it to work. I even manually loaded the assembly having the controllers, and I could see it loaded in the AppDomain when debugging, but for some reason it still wouldn't work. I could even verify that the List was populated with the controller types, but strangely no luck. Definitely open to any suggestions on this since I will be using a similar approach in the future on another project.

How to I find out what namespace a missing identifier belongs to?

When I compile my c# project in visual studio, I get the error ...
Error 1 The name 'FilterConfig' does not exist in the current context ...
I guess I need to add a 'using' statement or add a package or something. In general, whats the best ways to try and figure out what package/namespace missing things might belong to? E.g is there a way to search all common packages to find a member?
I've searched on msdn but cant seem to find it.....
http://social.msdn.microsoft.com/Search/en-US?query=filterconfig&emptyWatermark=true&searchButtonTooltip=Search%20MSDN&ac=4#refinementChanges=33,26,59&pageNumber=1&showMore=false
Update: This particular example is for MVC4, however I am interested for a general solution (or multiple solutions) as I work on console apps also.
I've often come across this problem when using incomplete tutorials I've found on the web. So the references may not be present at all. Usually they turn out to be for Microsoft.
General Troubleshooting Steps
Right-click on the identifier. In the context menu, you should see Resolveā€¦ &rtri;. In the sub menu you should see two lists which contain all of the namespaces in all the project's loaded references which contain a symbol with that name.
Selecting an item from the first list will add a using directive to the current file. Selecting an item from the second list will modify that use of the identifier to be globally qualified. Just select the option you want to use.
If the identifier cannot be found in any of the loaded references (either you are missing a reference, or it's a typo), then you won't see this list. In that case, you should make sure all the references are loaded correctly (there will typically be an exclamation mark next to it could not be loaded) and check the spelling of the identifier.
If all the references are correctly loaded, and your sure the identifier is spelled correctly, it's likely the symbol was renamed, or removed entirely from the project. Using the Renameā€¦ tool (also found by right-clicking on an identifier) can help to avoid this in the future. It's also possible the code snippet in question was taken out of a project where that symbol was defined and you need to include more code from that project to make the code functional. Finally, it may simply be that you're just missing a necessary reference. If this is the case you should investigate where this code came from and what libraries it uses, either by asking the original developer, or if it came from an online source, review the source to see if any more details are provided.
Regarding This Specific Issue
That's about it for general troubleshooting. However, for your specific issue, these steps may only get you so far, and you need to know more about where this exact class comes from in order to resolve it. Microsoft's MVC4 project template includes a number files in the App_Start folder. You typically start out with something like this (NOTE: not every MVC4 project template will contain the same files):
And these will typically be referenced in your Global.asax file like this:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
}
If this is where you're seeing the issue, it's likely that somehow the project was broken in some way. Either the FilterConfig class was renamed or removed entirely (as I stated above). It's also possible that the project started out life as an MVC3 template (which I believe didn't include the FilterConfig class) or perhaps a pre-release version of MVC4, and in migrating to full MVC4 template, this was left out. In any case, I would recommend you create a brand new MVC4 project and see what's different between the your project and the new one.
Now, if for any reason the new project doesn't compile and run like it should, then the template itself is probably damaged somehow. In this case, I'd recommend you uninstall MVC4 and re-install it from the official source.
Additionally to what p.s.w.g said (which you should normally do): I guess that you're using ASP.NET MVC or ASP.NET Web API and that the FilterConfig class is located in the *App_Start* folder. If so, you should remove the *App_Start* from the end of the namespace. After doing so you can call it without a problem in the Global.asax file.
Like said, normally you should use the solution provided by p.s.w.g, but for startup tasks this is the way Microsoft does it in its templates.

Can I add an ASPX page to an MVC project WITHOUT involving any Controllers?

I have an interesting situation where I need to quickly provide a feature to a customer prior to our normal build schedule and outside of our normal build repository. I need it to go live tonight, without a recompile.
Our site is deployed with everything compiled into a DLL, besides the Views. This means that at anytime I can edit the Views on the fly in the middle of the day. Is there a way I can add a new page that can be invoked via HTTP GET or POST so that I can do some things I would normally do in a Controller without actually making a new Action, etc? I know this is not a good methodology and it won't be the long term solution, I just need a plan... business is business after all.
Edit: I also cannot edit the Global.asax routing table, it is also compiled.
The first thing you'd have to do is pull out your Routes into XML files so you could add routes on the fly (all it'd do is recycle the App-Pool). I also recommend pulling the Routes out of the web.config into their own .config file, that's referenced in the web.config.
The second thing is you would have to mix Webforms with ASP.NET MVC if you wanted to do this.
It's important to note that using UrlParameter.Optional is problematic with XML based routing, at least I never got it to work.
I believe because of the way routing works in MVC it will try to find a valid path using the Routing system first. Failing that it should look for the aspx page using the normal method of just looking for the file. Keep in mind that aspx files (or razor files) that are just asp.net pages should not be in the Views folder, as MVC apps are configured to refuse serving up files in that directory. I'm assuming your're just talking about a single page or two? Anything more complex than that and I would look at trying to separate them more strongly as in the article mentioned above.
You could mix classic webforms with MVC.
I'm almost positive you could add a new Controller class to the App_Code folder and it would get picked up without a compile needed.
I guess it all depends if you have a convention based route that will hit it or not.

Categories

Resources