I have an ASP.NET MVC 5 controller using attribute routes that doesn't appear to be working with DELETE operations.
[Route("deletealbum/{id}")]
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult DeleteAlbum(int id)
{
// rest of the code omitted here
return Json(true, JsonRequestBehavior.AllowGet);
}
I explicitly changed the route name to deletename to rule out other route overload conflicts.
The above action does not fire - I get a 404 not found from IIS. However, if I switch the above action to a HttpVerbs.Get the route is found no problem.
First time in a long time building an API with MVC instead of Web API, and I can't figure out why the route is not firing - it almost looks like any DELETE operations are blocked. I see the same behavior in a different controller - GET works fine, but DELETE operation returns a 404. Is there some configuration setting that needs to be flipped to enable additional verbs perhaps?
This could be due to an IIS configuration issue as outlined in more detail in this answer to a similar question
You may need to enable DELETE (and PUT if you need it) in your IIS config something like this:
Before:
<add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
After:
<add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Related
I have mini-profiler working, but now I am trying to restrict access by setting functions as described under "Profiler Security" at http://miniprofiler.com/
MiniProfiler.Settings.Results_Authorize = IsUserAllowedToSeeMiniProfilerUI;
MiniProfiler.Settings.Results_List_Authorize = IsUserAllowedToSeeMiniProfilerUI;
My IsUserAllowedToSeeMiniProfilerUI function needs to look at the results of the ClaimsPrincipal, which is modified by a custom globally registered Authorization filter.
When I watch the calls, the primary request is authorized as expected, and IsUserAllowedToSeeMiniProfilerUI returns true. However, the http request that retrieves the profiler results (~/mini-profiler-resources/results or ~/mini-profiler-resources/results-index) bypasses my global authorization filter, so the ClaimsPrincipal isn't correctly modified for that request, and IsUserAllowedToSeeMiniProfilerUI incorrectly returns false due to that.
I register mini-profiler's filter as GlobalFilters.Filters.Add(new ProfilingActionFilter()), and also have the handler registered in the web.config as
<system.webServer>
<handlers>
<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*"
type="System.Web.Routing.UrlRoutingModule"
resourceType="Unspecified" preCondition="integratedMode" />
<!-- ... -->
</handlers>
My custom authorization filter is registered in the Global.asax by adding it as GlobalFilters.Filters.Add(new MyAuthorizationFilter())
Why is mini-profiler bypassing my authorization filter?
GlobalFilters is centric to the MVC framework. So by default the globally registered authorization filters will only take effect for requests handled by the mvc framework - not for all http requests.
MiniProfiler implements its client-side results in a single class MiniProfilerHandler that implements both IRouteHandler and IHttpHandler. (The default profiler provider WebRequestProfilerProvider ensures that the routes for MiniProfilerHandler are registered. The web.config registration of UrlRoutingModule ensures that the mini profiler urls are actually routed.)
Thus mini profiler handles the profiler results http requests directly as an http handler that is located by routing - outside of the normal MVC request flow.
So it is necessary to handle any custom authorization logic in the e.g. IsUserAllowedToSeeMiniProfilerUI method taking into account that any authorization filters (or other action filters for that matter) are not guaranteed to have run. Note however, that it appears that Results_Authorize is also invoked at some stage once profiling is started, so you also must handle the case where your filters have run.
See also: Understanding the MVC Application Execution Process
I am using MVC Actionfilter (Global) to call db to get user data and i try to store that in session.
Coding as mentioned in Dependency Injection in ASP.net Session_Start method.
Everything works fine in local machine.
But in production machine, my filterContext.HttpContext.Session (filterContext being ActionExecutingContext) is always null.
I dont know what more information i can give, but if somebody asks questions I am ready to provide more answers.
Please let me know what i can check.
Adding the below to the web.config fixed the problem, although i dont know why it has to be done.
<system.webServer>
<modules>
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
</modules>
</system.webServer>
I would like to define a catch all all route that catches all requests.
I've tried the following route definition:
routes.MapRoute("CatchAll", "{*stuff}", new { controller = "Proxy", action = "Proxify", stuff = UrlParameter.Optional });
It catches all request as long as they doesn't contain filenames like in
http://localhost/vault/11/Test.docx
How can I define a route that treats everyting after the hostname as a string an passes that to my controller?
Solution
I've found a solution to the problem by inserting the following to my web.config file:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
I believe that by default, ASP.NET includes many modules for handling different file types. This means that if the requested resource matches one of those known files types (eg. *.asp or *.aspx) then the corresponding module will handle that request instead of the MVC one.
I have a MVC4 web app with the following controller
[Authorize]
public class AccountController : BaseController
{
[AllowAnonymous]
public ActionResult SignInRegister(LoginModel loginModel, string returnUrl)
{
//some implementation
}
//other secured actions
}
This is working as expected when running locally, but as soon as I deploy it to the Free Azure Website I get a 401 error code with the message: You do not have permission to view this directory or page.
Removing the [Authorize] attribute and redeploying works as expected, adding it again and redeploying brings back the problem.
I even tried the fully qualified class names: System.Web.Mvc.Authorize and System.Web.Mvc.AllowAnonymous with the same results.
The app is using .NET 4.5 and the Azure Website is also configured to use 4.5.
UPDATE:
The BaseController has an action that returns the Header as partial view which was not decorated with [AllowAnonymous]. Locally it resulted in the page being displayed without the header, but on Azure Websites the response was cut off and only returned with the error message mentioned above. I had not realized the header was missing until I purposely looked into it.
Now the question begs to be asked: why is Azure Websites overriding the response?
The BaseController has an action that returns the Header as partial view which was not decorated with [AllowAnonymous]. Locally it resulted in the page being displayed without the header, but on Azure Websites the response was cut off and only returned with the error message mentioned above. I had not realized the header was missing until I purposely looked into it.
Now the question begs to be asked: why is Azure Websites overriding the response?
I had the exact same problem and like Jonas' update says, you need to look out for Actions that return Partial Views AND have the [Authorize] attribute.
What you need to do is to remove the [Authorize] attribute and then if your action needs the user to be authenticated to render properly, have your code handle the unauthorized case.
Example is if your page displays the currently logged in user's name via a Partial. Have your action display an empty string or something else if the currently logged in user is not available.
Check your web.config if you have
<authorization>
<deny users="?" />
</authorization>
its override [AllowAnonymous]
Add to web.config section:
<location path="YourController/AnonymousMethod">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
to allow anonymous access for AnonymousMethod
By ASP.NET MVC plugin architecture, Plug-in architecture for ASP.NET MVC
I have separated DLL(plugin) which contains the views, css and javascript files in the resources. So my own VirtualPathProvider will load the content out from the DLL if that is for the plugin. It works all fine during development. But It appears not working once I deployed it in IIS. (I mapped the whidcard in IIS 6 and the views are showing)
I have registered my VirtualPathProvider in global.asax as
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider());
}
For example.
http://localhost/Plugin/MyPlugin.dll/Styles.MyStyles.css
This should be loaded from the plugin.dll but IIS returns 404.
I guess the static files are all handled by the IIS and not went through asp.net and my VirtualPathProvider ? Is there way to get around this? Please shed some light.
Thanks in advance.
If this is IIS 6 you will need a wildcard mapping. See this blog post from Phil Haack.
I've found the workaround by adding the staticFileHandler in the web.config httpHandlers element.
<add verb="GET,HEAD,POST" path="*" type="System.Web.StaticFileHandler" validate="true" />
I've had a number of problems getting an external compiled library containing resources and controllers to work in our MVC environment. It's used across multiple projects and different errors have surfaced in different projects so here's all the things I had to do (so far) to ensure static file handling works:
Include StaticFileHandler in web.config, e.g.:
<add verb="GET,HEAD" path="*.js" name="Static for js" type="System.Web.StaticFileHandler" />
Ensure Static items are ignored in routing:
routes.IgnoreRoute("{*staticfile}", new { staticfile = #".*\
.(css|js|gif|jpg)(/.*)?" });
Register a Virtual Path Provider, e.g.:
System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedResourceVirtualPathProvider.Vpp(assemblies.ToArray())
{
//you can do a specific assembly registration too. If you provide the assemly source path, it can read
//from the source file so you can change the content while the app is running without needing to rebuild
//{typeof(SomeAssembly.SomeClass).Assembly, #"..\SomeAssembly"}
});
Not required for static files but worth mentioning are what was needed to get the views / controllers working, which was adding MVCContrib and registering the embedded view engine:
PortableAreaRegistration.RegisterEmbeddedViewEngine();