Does any one know how to setup correct IoC (Autofac) and use it with Sitecore MVC ?
I have created a specific Pipeline but it seams like resolving doesn't work when sitecore render page (Controller rendering).
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor type="MyLib.AutofacProcessor, MyLib" />
</initialize>
</pipelines>
</sitecore>
</configuration>
public class AutofacProcessor
{
public void Process(PipelineArgs args)
{
AutofacProcessor.Start();
}
public static void Start()
{
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().PropertiesAutowired();
var container = builder.Build();
IDependencyResolver resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
}
}
But my property in controller is null when sitecore call it.
How to register it in Sitecore term ? In Regular ASP MVC it is quite easy.
You also need to override Sitecore's default ControllerFactory.
<processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"/>
Here's an example for NInject, it should be easily modified to do the same with AutoFAC: http://blog.istern.dk/2012/10/23/sitecore-mvc-new-ninject-controller-factory-clean-version/
I create a blog post around how to use Autofac with Sitecore MVC in order to resolve dependencies:
http://sitecorecorner.com/2016/01/20/sitecore-mvc-autofac-dependency-resolution/
You can find the code on BitBucket
The basic idea is to create an AutofacContainerFactory - to create your Container. AutofacControllerFactory - which you are going to use to resolve the dependancy and Hijack the <processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc">
processor.
I've got a legacy Web.Forms app that been partially rewritten to MVC. MVC part uses autofac as a dependency injection container.
MVC part have custom filter defined:
public class CustomActionFilter : ActionFilterAttribute
{
protected ILogger Logger { get; set; }
public CustomActionFilter(ILogger logger) { Logger = logger; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Logger.Log("OnActionExecuting");
}
}
It works fine when Web.Forms integration is disabled in web.config. Hovewer, when I try to use Web.Forms autofac integration, I've got the NullReferenceException related to AutofacFilterProvider somewhere in autofac internals (stack trace).
Global.asax.cs: http://pastebin.com/437Tnp0t
web.config: http://pastebin.com/5pU6SH6c
Note that CustomActionFilter is registered as global filter, thus it is registered with autofac:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(DependencyResolver.Current.GetService<CustomActionFilter>());
}
}
I've tried:
using separate containers for MVC and Web.Forms - same result
Use property injection instead of constructor - same result
Explicitly trigger dependencies resolution on web.forms pages (like this) - worked
So, the question is, are there any way to provide behind-the-scenes dependency resolution both to MVC and web.forms part. I'm new to autofac and somewhat new to dependency injection containers in general, so I might just miss something obvious.
Update: error has nothing to do with custom filters. If I remove all references to custom filters the bug behavior still the same, even the stack trace.
Actually there are two bugs? in Autofac which causing this behavior:
Bug #1: As side effect of the fix of Issue 351 the AutofacDependencyResolver needs to registered in the created Request bound LifeTimeScopes. The MVC intergration does this but the Winforms integration of course does not.
Bug? #2: Both the RequestLifetimeScopeProvider and the ContainerProvider stores the created ILifetimeScope with the same key HttpContext.Current.Items:
static ILifetimeScope LifetimeScope
{
get { return (ILifetimeScope)HttpContext.Current.Items[typeof(ILifetimeScope)]; }
set { HttpContext.Current.Items[typeof(ILifetimeScope)] = value; }
}
So there is a little bit race condition here because depending on which module gets executed first the WebForms or the MVC intergartion ILifetimeScope wins. So if the WebForms module wins the AutofacDependencyResolver won't be registered and you get the nice non descriptive exception.
Fix/workaround:
But there is an simple workaround: you just need to register the AutofacDependencyResolver in the ContainerProvider requestLifetimeConfiguration so no matter which one wins (WebForm vs. MVC) the AutofacDependencyResolver will be always registered:
var autofacDependencyResolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(autofacDependencyResolver);
_containerProvider = new ContainerProvider(container, requestContainerBuilder =>
requestContainerBuilder.RegisterInstance(autofacDependencyResolver)
.As<AutofacDependencyResolver>());
I'm trying to get an API Controller to work inside an ASP.NET MVC 4 web app. However, every request results in a 404 and I'm stumped. :/
I have the standard API controller route from the project template defined like:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The registration is invoked in Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
// Register API routes
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
I have a basic API controller like this:
namespace Website.Controllers
{
public class FavoritesController : ApiController
{
// GET api/<controller>
public IEnumerable<string> Get()
{
return new [] { "first", "second" };
}
// PUT api/<controller>/5
public void Put(int id)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
Now, when I browse to localhost:59900/api/Favorites I expect the Get method to be invoked, but instead I get a 404 status code and the following response:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:59900/api/Favorites'.
</Message>
<MessageDetail>
No type was found that matches the controller named 'Favorites'.
</MessageDetail>
</Error>
Any help would be greatly appreciated, I'm losing my mind a little bit over here. :) Thanks!
One thing I ran into was having my configurations registered in the wrong order in my GLobal.asax file for instance:
Right Order:
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
Wrong Order:
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
WebApiConfig.Register(GlobalConfiguration.Configuration);
Just saying, this was my problem and changing the order is obvious, but sometimes overlooked and can cause much frustration.
Had essentially the same problem, solved in my case by adding:
<modules runAllManagedModulesForAllRequests="true" />
to the
<system.webServer>
</system.webServer>
section of web.config
I have been working on a problem similar to this and it took me ages to find the problem. It is not the solution for this particular post, but hopefully adding this will save someone some time trying to find the issue when they are searching for why they might be getting a 404 error for their controller.
Basically, I had spelt "Controller" wrong at the end of my class name. Simple as that!
Add following line
GlobalConfiguration.Configure(WebApiConfig.Register);
in Application_Start() function in Global.ascx.cs file.
I had the same problem, then I found out that I had duplicate api controller class names in other project and despite the fact that the "routePrefix" and namespace and project name were different but still they returned 404, I changed the class names and it worked.
Similar problem with an embarrassingly simple solution - make sure your API methods are public. Leaving off any method access modifier will return an HTTP 404 too.
Will return 404:
List<CustomerInvitation> GetInvitations(){
Will execute as expected:
public List<CustomerInvitation> GetInvitations(){
For reasons that aren't clear to me I had declared all of my Methods / Actions as static - apparently if you do this it doesn't work. So just drop the static off
[AllowAnonymous]
[Route()]
public static HttpResponseMessage Get()
{
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
Became:-
[AllowAnonymous]
[Route()]
public HttpResponseMessage Get()
{
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
Create a Route attribute for your method.
example
[Route("api/Get")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
You can call like these http://localhost/api/Get
Had this problem. Had to uncheck Precompile during publishing.
I'm a bit stumped, not sure if this was due to an HTTP output caching issue.
Anyways, "all of a sudden it started working properly". :/ So, the example above worked without me adding or changing anything.
Guess the code just had to sit and cook overnight... :)
Thanks for helping, guys!
I'm going to add my solution here because I personally hate the ones which edit the web.config without explaining what is going on.
For me it was how the default Handler Mappings are set in IIS. To check this...
Open IIS Manager
Click on the root node of your server (usually the name of the server)
Open "Handler Mappings"
Under Actions in the right pane, click "View ordered list"
This is the order of handlers that process a request. If yours are like mine, the "ExtensionlessUrlHandler-*" handlers are all below the StaticFile handler. Well that isn't going to work because the StaticFile handler has a wildcard of * and will return a 404 before even getting to an extensionless controller.
So rearranging this and moving the "ExtensionlessUrlHandler-*" above the wildcard handlers of TRACE, OPTIONS and StaticFile will then have the Extensionless handler activated first and should allow your controllers, in any website running in the system, to respond correctly.
Note:
This is basically what happens when you remove and add the modules in the web.config but a single place to solve it for everything. And it doesn't require extra code!
Check that if your controller class has the [RoutePrefix("somepath")] attribute, that all controller methods also have a [Route()] attribute set.
I've run into this issue as well and was scratching my head for some time.
WebApiConfig.Register(GlobalConfiguration.Configuration);
Should be first in App_start event. I have tried it at last position in APP_start event, but that did not work.
I found this in a comment here: https://andrewlock.net/when-asp-net-core-cant-find-your-controller-debugging-application-parts/
Add the following to your Program.cs:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// DP: I don't know the purpose of this, but without it, all controllers report 404
endpoints.MapControllerRoute("default", "WTF is this");
});
For me this is all it took to make it work after hours of trying to find a solution. If this doesnt work for you, try adding
builder.Services.AddControllers();
Add this to <system.webServer> in your web.config:
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
Adding <modules runAllManagedModulesForAllRequests="true" /> also works but is not recommended due performance issues.
I have solved similar problem by attaching with debugger to application init. Just start webserver (for example, access localhost), attach to w3wp and see, if app initialization finished correctly. In my case there was exception, and controllers was not registered.
I had the same 404 issue and none of the up-voted solutions here worked. In my case I have a sub application with its own web.config and I had a clear tag inside the parent's httpModules web.config section. In IIS all of the parent's web.config settings applies to sub application.
<system.web>
<httpModules>
<clear/>
</httpModules>
</system.web>
The solution is to remove the 'clear' tag and possibly add inheritInChildApplications="false" in the parent's web.config. The inheritInChildApplications is for IIS to not apply the config settings to the sub application.
<location path="." inheritInChildApplications="false">
<system.web>
....
<system.web>
</location>
I have dozens of installations of my app with different clients which all worked fine and then this one just always returned 404 on all api calls. It turns out that when I created the application pool in IIS for this client it defaulted to .net framework 2.0 instead of 4.0 and I missed it. This caused the 404 error. Seems to me this should have been a 500 error. Very misleading Microsoft!
I had this problem: My Web API 2 project on .NET 4.7.2 was working as expected, then I changed the project properties to use a Specific Page path under the Web tab. When I ran it every time since, it was giving me a 404 error - it didn't even hit the controller.
Solution: I found the .vs hidden folder in my parent directory of my VS solution file (sometimes the same directory), and deleted it. When I opened my VS solution once more, cleaned it, and rebuilt it with the Rebuild option, it ran again. There was a problem with the cached files created by Visual Studio. When these were deleted, and the solution was rebuilt, the files were recreated.
If you manage the IIS and you are the one who have to create new site then check the "Application Pool" and be sure the CLR version must be selected. In my situation, it had been selected "No Managed Code". After changed to v4.0 it started to work.
i try above but not sucess all
add ms webhost and GlobalConfiguration.Configure(WebApiConfig.Register);
I've just installed ELMAH MVC (v2) into my web application but when I try to view the logs at /elmah I get the following exception
No component for supporting the service Elmah.Mvc.ElmahController was found
[ComponentNotFoundException: No component for supporting the service Elmah.Mvc.ElmahController was found]
Castle.MicroKernel.DefaultKernel.Resolve(Type service) +140
Castle.Windsor.WindsorContainer.Resolve(Type service) +40
N2.Engine.Castle.WindsorServiceContainer.Resolve(Type type) +40
N2.Engine.ContentEngine.Resolve(Type serviceType) +48
The web site includes the N2 CMS system which in turn uses Castle Windsor.
Any ideas on how I can resolve this?
I know this already has an accepted answer, and it's not entirely relevant to your question, but for anyone else not using N2 and running into issues with Elmah.MVC+Castle Windsor, you need to register the controllers in the Elmah.MVC assembly with Windsor. I made a simple installer to handle this for me:
public class ElamhInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromAssemblyNamed("Elmah.Mvc")
.BasedOn<IController>()
.LifestyleTransient());
}
}
Once I added this Castle seems to be able to find the ElmahController just fine.
Worked out the solution shortly after posting the question. I needed to register the Elmah controller with N2:
var engine = MvcEngine.Create();
engine.RegisterControllers(typeof(GlobalApplication).Assembly);
engine.RegisterControllers(typeof(ElmahController).Assembly);
ELMAH.MVC comes App_Start code, that uses Web.Activator to register ElmahController route.
So, it's strange for me, why Windor fails to load ElmahController. By default, it should try to resolve it by itself, then if not possible delegate to ControllerFactory.
Are you sure, application got restarted (iisreset.exe) after ELMAH installed?
I'm trying to register RequestContext for my IoC container (autofac). I do all the registration in Application_start.
The RequestContext registration looks like this:
builder.Register(x => HttpContext.Current.Request.RequestContext).As<RequestContext>();
this works fine on the dev webserver but in IIS 7 (integrated mode) the problem is that RequestContext context is not available in Application_start.
What can I do here ?
It appears there are two problems to be solved here:
How do you register RequestContext?
Why isn't RequestContext properly resolving?
The easiest thing you can do for registration if you're using the Autofac MVC integration is:
builder.RegisterModule<AutofacWebTypesModule>();
There is already a module that registers the various web abstractions (HttpContextBase, RequestContext, etc.) properly scoped to instance-per-HTTP-request. It's tested and will save you a lot of time.
If, instead, you want to register it manually yourself, doing what you have should work if you scope it to InstancePerHttpRequest (that way you don't get it over and over on each request).
Additionally, you can "chain" it into the current context like in the module:
builder.Register(c => new HttpContextWrapper(HttpContext.Current))
.As<HttpContextBase>()
.InstancePerHttpRequest();
builder.Register(c => c.Resolve<HttpRequestBase>().RequestContext)
.As<RequestContext>()
.InstancePerHttpRequest();
That takes care of the first part, but the second part is sort of tricky.
If you're getting errors at app startup because the RequestContext isn't available, then somewhere in your app you're trying to resolve something that uses RequestContext before you actually have a request. For example, an HttpModule implementation that is manually trying to resolve something that has RequestContext as a constructor parameter.
The lambda in the registration doesn't actually get evaluated until resolution, so the error is probably coming from something you're resolving that is trying to consume RequestContext too early.
In that case, the question is: How do you want to handle resolution when you try to resolve RequestContext and there's no request?
By default, you'll get an exception, which is probably what you're seeing now.
If you want it to be null instead, then do a registration like this:
// Register context as instance-per-dependency and handle the
// case where it's null. Also handle HttpException because IIS7
// can throw if you access HttpContext.Current too soon in app startup.
builder.Register(
c => {
try
{
var ctx = HttpContext.Current;
return ctx == null ? null : new HttpContextWrapper(ctx);
}
catch(HttpException)
{
return null;
}
}).As<HttpContextBase>();
// RequestContext also gets registered instance-per-dependency
// and handles the null context case.
builder.Register(
c => {
var ctx = c.Resolve<HttpRequestBase>();
return ctx == null ? null : ctx.RequestContext;
}).As<RequestContext>();
That should get you past the app-startup problem.
All that said... you should figure out what's trying to use RequestContext at application startup and see if you can fix the design. You shouldn't end up needing to do this sort of thing in normal circumstances.