I have a IRouteHander class which I use to resize images on the fly and add expire headers to them, Recently I moved to MVC5 and now updating my code. I tried to register the same route for that class in RouteConfig.cs
routes.Add(new Route("Image/{w}/{h}/{src}", new ThumbImageRouteHandler()));
but this route isn't working anymore like it was on MVC3 and giving 404 error in MVC5. Is there anything I am missing here? this route leads to
public class ThumbImageRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
HttpHanler httpHandler = new HttpHanler();
return httpHandler;
}
public class HttpHanler : IHttpHandler
{
public bool IsReusable
{
get
{
return false;
}
}
public void ProcessRequest(HttpContext context)
{
//Do something
}
}
}
}
Please help me fixing this issue. Thanks
After research I found out that I need to add a line in webconfig in order to make it work, here's how.
<system.webServer>
<handlers>
<add name="ApiURIs-ISAPI-Integrated-4.0-Image" path="/Image/*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Because IRouteHandler is generating re-sized images with a dynamic path, and IIS thinks this is the actual path to a directory because of dot(.) in the link and it thinks it's an extension, which is actually not. So we have to add a handler in Web.Config to make it work.
Related
I'm looking to properly configure System.Web.Handlers.TransferRequestHandler path attribute to handle both routes to WebApi REST actions and ODataController custom function in an ASP.NET WebApi 2 project.
My web.config file handlers are configured as follow in order to support custom ODataController functions call (see my related question here) :
<handlers>
<clear/>
<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>
</system.webServer>
Note that the path is set to /* and it works well when accessing custom OData functions on our ODataControllers
Nevertheless we also have an ApiController and when we access it, IIS doesn't properly handle the request and fails with the following details :
HTTP Error 500.0 - Internal Server Error
Internal Server Error
Detailed Error Information:
Module ManagedPipelineHandler
Notification ExecuteRequestHandler
Handler ExtensionlessUrlHandler-Integrated-4.0
Error Code 0x800703e9
If I set the TransferRequestHandler path to *. as suggested here the WebApi request get properly resolved however the ODataController request ends up not beeing found with HTTP 400 :
HTTP Error 404.4 - Not Found
The resource you are looking for does not have a handler associated with it.
Detailed Error Information:
Module IIS Web Core
Notification MapRequestHandler
Handler Not yet determined
Error Code 0x80070002
How can I properly configure it to handle both cases ?
++++ Edit : ++++
For the sake of clarity here is the queries I use to tests my controllers :
Custom odata function call : http://localhost:xxxx/myProject/odata/SomeModels/MyNamespace.MyCustomFunction(parameterA=123,parameterB=123)
Native odata GET call : http://localhost:xxxx/myProject/odata/SomeModels
Native web api GET call: http://localhost:xxxx/myProject/api/SomeOtherModel?parameterC=123
My web api controller :
public class SomeOtherModelsController : ApiController
{
public IHttpActionResult Get(int parameterC)
{
// ...
return Ok(/* some result */);
}
[HttpPost]
public IHttpActionResult Post(SomeOtherModel model)
{
// ...
return Ok(/* some result */);
}
}
My odata controller:
public class SomeModelController : ODataController
{
[EnableQuery]
public IHttpActionResult Get()
{
// ...
return Ok(/* some result*/);
}
[HttpGet]
[EnableQuery]
public IHttpActionResult MyCustomFunction(int parameterA, int parameterB)
{
// ...
return Ok(/* some result */);
}
[HttpGet]
[EnableQuery]
public IHttpActionResult AnotherCustomFunction()
{
// ...
return Ok(/* some result */);
}
}
Here is the web api configuration:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
and the odata configuration :
var builder = new ODataConventionModelBuilder
{
Namespace = "MyNamespace"
};
builder.EntitySet<SomeModelModel>("SomeModels");
var anotherCustomFunction = builder.EntityType<SomeModelModel>().Collection.Function("AnotherCustomFunction");
anotherCustomFunction.Returns<SomeResultValue>();
var myCustomFunction = builder.EntityType<SomeModel>().Collection.Function("MyCustomFunction");
myCustomFunction.Parameter<int>("parameterA");
myCustomFunction.Parameter<int>("parameterB");
myCustomFunction.ReturnsFromEntitySet<SomeModelModel>("SomeModels");
A possible solution, as proposed here, is to add <modules runAllManagedModulesForAllRequests="true" /> to <system.webServer> in the web.config file :
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
It turns out that adding this module makes the presence of System.Web.Handlers.TransferRequestHandler handler unnecessary.
Therefore the following system.webServer configuration is sufficient to handle both api query and custom OData function queries :
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
</handlers>
</system.webServer>
Nevertheless, I'm not confortable with this solution as I don't know exactlly what could be the effects of <modules runAllManagedModulesForAllRequests="true" />.
Starting from my previous answer, I've created a new model (AnotherModel) and a new ApiController (AnotherModelsController)
AnotherModel.cs
namespace DemoOdataFunction.Models
{
public class AnotherModel
{
public int Id { get; set; }
public int MyInt { get; set; }
public string MyString { get; set; }
}
}
AnotherModelsController.cs
namespace DemoOdataFunction.Controllers
{
public class AnotherModelsController : ApiController
{
public IHttpActionResult Get(int parameterC)
{
// ...
return Ok();
}
public IHttpActionResult Get()
{
// ...
return Ok("Ok");
}
[HttpPost]
public IHttpActionResult Post(AnotherModel model)
{
// ...
return Ok();
}
}
}
Without any other changes both Api and OData controller works.
GET
http://localhost:4186/api/AnotherModels?parameterC=1
GET
http://localhost:4186/api/AnotherModels
Post
http://localhost:4186/api/AnotherModels
{
"Id" : 1,
"MyInt" : 2,
"MyString" : "Hello"
}
GET
http://localhost:4186/odata/TestModels/MyNamespace.MyFunction(parA=1,parB=2)
I've also tried changing the "path" setting of web.config to * but that's fine.
I suggest you create a new project from scratch and compare it with yours.
Hi i want to change the Page redirection in webconfig programmatically.
i have following code in web config.
<location path="WebForm2.aspx">
<system.webServer>
<httpRedirect enabled="true" destination="http://google.com" httpResponseStatus="Permanent" />
</system.webServer>
</location>
i want to enable or disable the httpredirect programmatically using c#.
please suggest me how to do this.
I've tried the code suggested by Rahul but I wasn't able to change the <location> element of the Web.config programatically.
As an alternative you could write an HttpHandler to intercept the request to the WebForm2.aspx page and redirect the user to another URL:
Handler:
namespace StackOverflowHelp
{
public class RedirectHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
Uri uri = context.Request.Url;
if (uri.AbsolutePath == "/WebForm2.aspx.aspx")
context.Response.Redirect("http://google.com");
}
}
}
Handler registration in the Web.config:
<system.webServer>
<handlers>
<add verb="*" path="WebForm2.aspx"
name="RedirectHandler"
type="StackOverflowHelp.RedirectHandler"/>
</handlers>
I want to trap 404 page not founds to go to a nice little sexy page I've created.
Let's start at step 1 first.
1)---------
I have an Error.chstml in my Shared views folder.
2)---------
I have added:
<customErrors mode="On" />
to my Web.Config (in the root directory) inside system.web
3)----------
I have added:
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
to my Global.asax ApplicationStart method and added a FilterConfig.cs file to my App Start folder with the following code:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
4)------------
I then tried to add this to the customErrors XML:
<customErrors mode="On" defaultRedirect="/Error" />
5)--------------
I had tried to create my own ErrorController and used my routes to redirect to it... but they never get fired:
routes.MapRoute(
"404-PageNotFound",
"{*url}",
new { controller = "Error", action = "Error404" }
);
...
public class ErrorController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult Error404()
{
return View();
}
}
This still returns the ugly smelly web 1.0 error page :) : HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
What am I doing wrong???? Something that I thought would take like 20 seconds has ended up taking 2 hours lol
With your current routes it will fail to redirect to that Error404 action method. Start by removing the 404-PageNotFound route. Then rename Error404 method to Index. Don't forget to rename the view too.
public class ErrorController : Controller
{
public ViewResult Index()
{
return View();
}
}
Now when user is redirected to http://example.org/Error like you specified web.config, this action method will be called.
I have a MVC solution, which works with authorization for certain URLs based on the logged-in user.
I had managed this problem by using a protected method on the parent controller which checks if a user is administrator or not. This is the code:
[Authorize]
public abstract class ConfigurationController<E> : Controller where E : IPersistentVM, new()
{
//SOME OTHER CODE RIGHT HERE
protected ActionResult CheckPermission(string url, SPDCSS.Model.Rules.Enums.Permission.Permissions permission)
{
var user = Helper.GetLoggedInUser();
if (user.UserTypeId == (int)SPDCSS.Model.Rules.Enums.UserType.UserTypes.Administrator)
{
return View(url);
}
throw new UnauthorizedAccessException("Access Denied.");
}
}
And then, each inherited class calls this method this way:
namespace SPDCSS.Management.Web.Application.Controllers.Configuration
{
public class ChartController : ConfigurationController<ChartVM>
{
public ActionResult Chart()
{
return CheckPermission("~/Views/Configuration/Chart.cshtml",M.Enums.Permission.Permissions.Chart);
}
//MORE CODE HERE...
}
}
The problem is that I want to redirect for a specific view when I throw this exception, and I saw that most of people do it in the web.config file. I did it this way, but is not working:
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="~/Views/Shared/Error.cshtml">
<error statusCode="403" redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
</customErrors>
<!-- # some other code # -->
</system.web>
I think that maybe, the problem is on the status code which I had specified, but I don't what to use there. Any ideas about where the problem is?
My sitemap is at: http://localhost/scirranew/sitemap.ashx
<%# WebHandler Language="C#" Class="SiteMap" %>
using System;
using System.Web;
public class SiteMap : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/xml";
}
public bool IsReusable {
get {
return false;
}
}
}
As far as I know, google will be OK with this. But I would like it to be a .xml filetype for consistency throughout my site.
I've tried rewriting the URL:
<rewrite url="^~/Sitemap.xml" to="~/SiteMap.ashx" processing="stop"/>
But this doesn't work with the .xml extension.
Instead of using an ashx file, just put the code in an assembly and register the handler in web.config with any extension you like:
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="Sitemap.xml"
type="SiteMap, AssemblyContainingClass" />
</httpHandlers>
</system.web>
</configuration>