Is this possible to achieve?
I want to make a library (lets call it Foolib) that will automatically add an mvc controller with a fix route to all mvc applications that have a dependency on Foolib.
Foolib is to be used in several intranet applications that we are developing and I want to make sure that all applications that use of Foolib have an standard ability to receive a configuration object.
In Foolib there will be a controller something like:
public FooController
{
[Route("/Foo")]
public Post(object obj)
{
}
}
Would it be possible to register the controller automatically to all web applications that uses Foolib?
Normally the calls to register controllers are made in the Startup class, how would I hook in this extra controller, hopefully without having to burden the other mvc application developers with an "just add this line to your startup" solution?
According to the docs
"By default MVC will search the dependency tree and find controllers (even in other assemblies)."
So it should just work.
I have been trying to configure my Web API 2, that uses the Startup class to configure the API (OWIN Self-Hosting), for it to support the use of the Session object.
I am aware that a REST application should be statless, but I need to use the session anyway.
I have tried this solution, but it won't work.
I have also looked at multiple blog posts and articles that suggest using a custom RouteHandler that overrides the GetHttpHandler method to use a controller that implements IRequiresSessionState (as explained here). But my startup class uses HttpRouteCollection, and my method MapHttpRoute does not support the property RouteHandler.
I have tried moving the route configuration from my Startup class to the Application_Start in a Global.asax I have added, but it is not working either (the requests are not reaching the controllers).
Any suggestion would be much appreciated!
Thank you
I used to place my controllers into a separate Class Library project in Mvc Web Api. I used to add the following line in my web api project's global.asax to look for controllers in the separate project:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
I never had to do any other configuration, except for adding the above line. This has always worked fine for me.
However I am unable to use the above method to do the same in WebApi2. It just doesn't work. The WebApi2 project still tries to find the controllers in its own project's controllers folder.
-- Giving little summary update after 2 months (As I started bounty on this):
I have created a WebApiOne solution, it has 2 projects, the first one is WebApi project, and the second is a class library for controllers. If I add the reference to the controllers class library project into the WebApi project, all works as expected. i.e. if i go to http://mydevdomain.com/api/values i can see the correct output.
I have now create a second project called WebApiTwo, it has 2 projects, the first one is WebApi2 project, and the second is a class library for controllers. If I add the reference to the controllers class library project to the WebApi2 project, it doest NOT work as expected. i.e. if i go to http://mydevdomain.com/api/values i get "No type was found that matches the controller named 'values'."
for the first project i am not doing any custom settings at all, i do NOT have:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
in my global.asax, and i have not implemented any custom solutions proposed by StrathWeb in two of his blog posts, as i think its not applicable any more; because all works just by adding the reference of the controller project to the WebApi project.
So i would expect all to work same for WebApi2 ... but its not. Has anyone really tried doing this in WebAPi2 ?
I have just confirmed that this works fine. Things to check:
References: Does your main Web API project reference the external class library?
Routing: Have you set up any routes that might interfere with the external controllers?
Protection Level: Are the controllers in the external library public?
Inheritance: Do the controllers in the external library inherit from ApiController?
Versioning: Are both your Web API project and class library using the same version of the Web API libraries?
If it helps, I can package up my test solution and make it available to you.
Also, as a point to note, you don't need to tell Web API to find the controllers with the line you added to Global.asax, the system finds the controllers automatically provided you have them referenced.
It should work as is. Checklist
Inherit ApiController
End controller name with Controller. E.g. ValuesController
Make sure WebApi project and class library project reference same WebApi assemblies
Try to force routes using attribute routing
Clean the solution, manually remove bin folders and rebuild
Delete Temporary ASP.NET Files folders. WebApi and MVC cache controller lookup result
Call `config.MapHttpAttributeRoutes(); to ensure framework takes attribute routes into consideration
Make sure that the method you are calling is made to handle correct HTTP Verb (if it is a GET web method, you can call via browser URL, if it is POST you have to otherwise craft a web request)
This controller:
[RoutePrefix("MyValues")]
public class AbcController : ApiController
{
[HttpGet]
[Route("Get")]
public string Get()
{
return "Ok!";
}
}
matches this url:
http://localhost/MyValues/Get (note there is no /api/ in route because it wasn't specified in RoutePrefix.
Controller lookup caching:
This is default controller resolver. You will see in the source code that it caches lookup result.
/// <summary>
/// Returns a list of controllers available for the application.
/// </summary>
/// <returns>An <see cref="ICollection{Type}" /> of controllers.</returns>
public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
{
HttpControllerTypeCacheSerializer serializer = new HttpControllerTypeCacheSerializer();
// First, try reading from the cache on disk
List<Type> matchingTypes = ReadTypesFromCache(TypeCacheName, IsControllerTypePredicate, serializer);
if (matchingTypes != null)
{
return matchingTypes;
}
...
}
Was running into same scenario and #justmara set me on the right path. Here's how to accomplish the force loading of the dependent assemblies from #justmara's answer:
1) Override the DefaultAssembliesResolver class
public class MyNewAssembliesResolver : DefaultAssembliesResolver
{
public override ICollection<Assembly> GetAssemblies()
{
ICollection<Assembly> baseAssemblies = base.GetAssemblies();
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
var controllersAssembly = Assembly.LoadFrom(#"Path_to_Controller_DLL");
baseAssemblies.Add(controllersAssembly);
return baseAssemblies;
}
}
2) In the configuration section, replace the default with the new implementation
config.Services.Replace(typeof(IAssembliesResolver), new MyNewAssembliesResolver());
I cobbled this syntax together using pointers from this blog:
http://www.strathweb.com/2013/08/customizing-controller-discovery-in-asp-net-web-api/
As others have said, you know if you are running into this issue if you force the controller to load by directly referencing it. Another way is to example the results of CurrentDomain.GetAssemblies() and see if your assembly is in the list.
Also: If you are self-hosting using OWIN components you WILL run into this. When testing keep in mind that the DefaultAssembliesResolver will NOT kick in until the first WebAPI request is submitted (it took me awhile to realize that).
Are you sure that your referenced assembly was loaded BEFORE IAssembliesResolver service called?
Try to insert some dummy code in your application, something like
var a = new MyClassLibraryProject.Controllers.MyClass();
in configuration method (but don`t forget, that compiler can "optimize" this code and totally remove it, if "a" is never used).
I've had similar issue with assembly loading order. Ended up with force loading dependent assemblies on startup.
You need to tell webapi/mvc to load your referrenced assembly. You do that with the compilation/assemblies section in your web.config.
<compilation debug="true" targetFramework="4.5.2">
<assemblies>
<add assembly="XYZ.SomeAssembly" />
</assemblies>
</compilation>
Simple as that. You can do it with code the way #user1821052 suggested, but this web.config version will have the same effect.
Apart from what has been said already:
Make sure you don't have two controllers of the same name in different namespaces.
Just had the case where one controller (foo.UserApiController) should be partially migrated to a new namespace (bar.UserApiController) and URI. The old controller was mapped by convention to /userapi, the new one was attribute-routed via RoutePrefix["api/users"]. The new controller didn't work until I renamed it to bar.UserFooApiController.
When using AttributeRouting it is easily forgettable to decorate your methods with the Route Attribute, especially when you are using the RoutePrefix Attribute on your controller class. It seems like your controller assembly wasn't picked up by the web api pipeline then.
If your class library is built with EF then make sure you have the connection string specified in the App.config for the class library project, AND in the Web.config for your Web API MVC project.
I am creating a RESTful webservice using ASP.NET MVC (not ASP.NET Web API). What I want to do is have every method in the controller return their result based on an input parameter (i.e. json or xml).
If I were using ASP.NET Web API, the HttpResponseMessage works for this purpose. When I attempt to return an HttpResponseMessage from a controller in ASP.NET MVC, there is no detail.
I have read that in this approach, I am supposed to use ActionResult. If I do this, then I need to create an XmlResult that inherits from ActionResult since it is not supported.
My question is why HttpResponseMessage does not work the same in both situations. I understand that in Web API, we inherit from ApiController and in ASP.NET MVC we inherit from System.Web.Mvc.Controller.
Any help is greatly appreciated.
Thanks,
EDIT 1
Much thanks to Fals for his input. My problem was in how to create an empty website and add all of the necessary functionality in. The solution was to use Nuget to get the packages mentioned in the comments and then to follow the steps in How to integrate asp.net mvc to Web Site Project.
Web Api is a Framework to develop Restfull services, based on HTTP. This framework was separeted into another assembly System.Web.Http, so you can host it everywhere, not only in IIS. Web API works directly with HTTP Request / Response, then every controller inherit from IHttpController.
Getting Started with ASP.NET Web API
MVC has It's implementation on System.Web.Mvc. coupled with the ASP.NET Framework, then you must use It inside an Web Application. Every MVC controller inherits from IController that makes an abstraction layer between you and the real HttpRequest.
You can still access the request using HttpContext.Response directly in your MVC controller, or as you said, inheriting a new ActionResult to do the job, for example:
public class NotFoundActionResult : ActionResult
{
private string _viewName;
public NotFoundActionResult()
{
}
public NotFoundActionResult(string viewName)
{
_viewName = viewName;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.StatusCode = 404;
context.HttpContext.Response.TrySkipIisCustomErrors = true;
new ViewResult { ViewName = string.IsNullOrEmpty(_viewName) ? "Error" : _viewName}.ExecuteResult(context);
}
}
This ActionResult has the meaning of respond thought HTTP Error.
As a matter of fact, it is indeed possible. You basically have two options:
develop your custom ActionResult types, which can be an heavy-lifting work and also quite hard to mantain.
add WebAPI support to your website.
I suggest you to do the latter, so you will have the best of two worlds. To do that, you should do the following:
Install the following Web API packages using NuGet: Microsoft.AspNet.WebApi.Core and Microsoft.AspNet.WebApi.WebHost.
Add one or more ApiControllers to your /Controllers/ folder.
Add a WebApiConfig.cs file to your /App_Config/ folder where you can define your Web API routing scheme and also register that class within Global.asax.cs (or Startup.cs) file.
The whole procedure is fully explained here: the various steps, together with their pros-cons and various alternatives you can take depending on your specific scenario, are documented in this post on my blog.
Currently I have an MVC application which also contains WebApi controllers.
I've set-up StructureMap to initialize using default conventions which handles service dependencies for both MVC and WebApi. This all works perfectly.
However, I have one Authentication service dependency which should be injected for WebApi and a different implementation for MVC. Since StructureMap has the same initialization bootstrap code, how do I switch depending on whether the request coming in is a WebApi endpoint or and Mvc controller endpoint?
Don't know if this is the best way of achieving this but I use the ObjectFactory.Configure method to override the initialization registries on boot-up but do this inside each SetResolver on Mvc's DependencyResolver.SetResolver and on WebApi's GlobalConfiguration.Configuration.ServiceResolver.SetResolver.
e.g.
ObjectFactory.Configure(x => x.For<IAuthenticationService>()
.Use(s => s.GetInstance<IMvcAuthenticationService>()));
and
ObjectFactory.Configure(x => x.For<IAuthenticationService>()
.Use(s => s.GetInstance<IWebApiAuthenticationService>()));