Invoke ASP.NET MVC Controller When Requesting .html file - asp.net-mvc

I need to add some new life to a legacy application :)
I'd like to call an MVC controller when a "static" HTML page is requested in order to add some markup to the page before returning it to the client.
I tried to follow the approach found in this thread: How to read web.config settings in .html page?
...but even though I have this route defined:
routes.MapRoute(
name: "Topic",
url: "html/{fileName}.html",
defaults: new { controller = "Topic", action = "Index" });
the controller is not being called. I have my web.config defined with:
<remove name="WebServiceHandlerFactory-Integrated" />
<add name="HTML" path="*.html" verb="*"
type="System.Web.UI.PageHandlerFactory"
resourceType="File" preCondition="integratedMode" />
I suspect that I need to call something else besides the PageHandlerFactory or perhaps the issue is something entirely different.
UPDATE: My dev environment is working with integrated pipeline mode, but I need to check if my production environment will support it.

If you do this:
routes.RouteExistingFiles = true;
You should find this works - even without the handler addition. In the controller you can load the HTML directly using the HostingEnvironment.VirtualPathProvider's GetFile method and do something with it - or better still just use a normal MVC view that renders the same content as the static file, just with your additions.
Although be aware that this means any files that are potentially caught by any routes will be pushed into the MVC pipeline. This isn't generally a concern, however, if decent separation of routes and physical paths is used.

I setup the same situation as you and it worked well for me, so you have the key components in place. Some things to keep in mind for the testing and troubleshooting:
Your web.config does need the build provider for the html extension:
<system.web>
<compilation>
<buildProviders>
<add extension=".html"
type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
</compilation>
</system.web>
A copy and paste of your handlers works for me, so that looks good.
And a copy and paste of your MapRoute works for me too, although I used the default Home controller in a clean project. So as a double check just confirm that you have a controller called Topic with an ActionResult method called Index().
And make sure that your url is localhost.com:{port}/html/test.html with the /html/ in the path since your rule asks for that.
Another good test is to change your MapRoute to use aspx instead and test an aspx page and see if that works. That will confirm whether or not it's the IIS mappings or if it's the MVC rules. If it works with aspx then the issue is related to the handler, but if it fails with aspx too then it's something with MVC.
Also confirm that you're using IIS Express and not Cassini. Cassini will not handle that correctly, but IIS Express will. You can confirm by right-clicking on your project and you should see a menu option called "Use Visual Studio Development Studio...". That will only exist if you are currently using IIS Express.

Related

routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); [duplicate]

What is routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
I cannot find any .axd file in my project, can I remove this route rule?
.axd files don't exist physically. ASP.NET uses URLs with .axd extensions (ScriptResource.axd and WebResource.axd) internally, and they are handled by an HttpHandler.
Therefore, you should keep this rule, to prevent ASP.NET MVC from trying to handle the request instead of letting the dedicated HttpHandler do it.
Some Background
If you open up this file:
%WINDIR%\Microsoft.NET\Framework\version\Config\Web.config
you will find this within the file:
<add path="WebResource.axd"
verb="GET"
type="System.Web.Handlers.AssemblyResourceLoader"
validate="True" />
That is basically telling the Asp.NET runtime: "Hey asp.net dude, if a request comes for WebResource.axd then use AssemblyResourceLoader to process the request."
Please do note that WebResource.axd is NOT a file but simply a map (if I may say) to AssemblyResourceLoader. It is the name under which the handler is registered. On my machine, I found the following .axd handlers:
<add path="eurl.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" />
<add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="True" />
<add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True" />
<add verb="*" path="*_AppService.axd"
Ok, so what does that handler do?
The AssemblyResourceLoader knows how to look for embedded files within an assembly so it can serve it (send it to the client i.e. a browser). For example, in asp.net web forms, if you use the validation controls, they depend on some javascript to show the errors on the web page. However, that javascript is embedded in an assembly. The browser needs the javascript so you will see this in the html of the page:
<script src="/YourSite/WebResource.axd?d=fs7zUa...&t=6342..." type="text/javascript"></script>
The AssemblyResourceLoader will find the assembly where the javascript is embedded using the information in the querystring and return the javascript.
Back to the Question
So to answer the question, what is:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
That is telling the routing engine that we will not be processing those requests that match that route pattern. In other words, we will not process .axd requests. Why? Because MVC itself is an HttpHandler similar to .axd and .aspx and many other handlers that are in the web.config file. The MVC handler does not know how to process the request such as looking for embedded resources in an assembly-the AssemblyResourceLoader knows how to do that. MVC knows how to do, well everything it does which is beyond the scope of this question and answer.
The route with the pattern {resource}.axd/{*pathInfo} is included to prevent requests for the Web resource files such as WebResource.axd or ScriptResource.axd from being passed to a controller.
Read link:
http://msdn.microsoft.com/en-us/library/cc668201%28v=vs.100%29.aspx
You can also specify that routing should not handle certain URL requests. You prevent routing from handling certain requests by defining a route and specifying that the StopRoutingHandler class should be used to handle that pattern. When a request is handled by a StopRoutingHandler object, the StopRoutingHandler object blocks any additional processing of the request as a route. Instead, the request is processed as an ASP.NET page, Web service, or other ASP.NET endpoint. You can use the RouteCollection.Ignore method (or RouteCollectionExtensions.IgnoreRoute for MVC applications) to create routes that use the StopRoutingHandler class.
Take a look in the below link:
http://haacked.com/archive/2008/07/14/make-routing-ignore-requests-for-a-file-extension.aspx
Those are not files (they don't exist on disk) - they are just names under which some HTTP handlers are registered.

MVC3 Web Application Will Not Publish

I am trying to learn MVC 3, so I am a noob. For now, I just want to make a basic site, that is an HTML page using jQuery and CSS. While I am using MVC, I don't really need a model, since there is not really any data being passed to the application. However, this is creating a problem for me, because I am getting a HTTP 403.14 Forbidden error when I try to publish this site. I think that there is something wrong with the way the application is structured that will not allow it to execute properly when I got to localhost:1081 web site. Here is all I have:
HomeController.cs
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
}
}
This just returns the view of Index.cshtml.
Index.cshtml:
#{ViewBag.Title = "My Web Site";} <h2>Web Site Title</h2>
All of my HTML code was put into _Layout.cshtml. jQuery and CSS are used. The site works fine when I do the debug option, but when I try to publish it gives me 403.14 forbidden. I have run the inline command aspnet_regiis -i and it seemed to work, but did not allow the project to run.
Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
If I move the code in _Layout to Index, it doesn't work. Is there a way I should be linking this to Index.cshtml?
Web.config:
<system.webServer>
<defaultDocument enabled="true">
<files>
<add value="_Layout.cshtml" />
</files>
</defaultDocument>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true"/>
I do not want directory browsing, and I have tried to play with this option as well. If I enable, it allows me to see the contents but does not render the page.
So two questions: 1.) Do I need to have a model, even though I am not passing any data to the application, just trying to render a site? 2.) Is my site set up / structured properly or what exactly am I doing wrong here?
Thanks,
Nick
No, you don't need a model.
First, don't use the default document. MVC overrides the default document handling and uses the route system.
Second, you don't want to try and use the Layout page as your document. Layout is like a master page, and is used to create a wrapper around your real document.
Third, saying "will not publish" means that you are having problems actually publishing the site via the publish mechanism. Your problem is not that you can't publish, because obviously it is doing so, but that your site isn't executing.
Fourth, 403.14 means it's trying to list the contents of directory, but this shouldn't happen if MVC is configured correctly because MVC's routing takes over. This means you have a problem somewhere in the asp.net pipeline.
Where are you publishing to? Did you configure IIS to setup a site at this location? Given that you are trying to access the site from a different port number, It would seem to me that you have not setup IIS to do this and are instead trying to use the same port that's used for debugging.
In order to publish a site, IIS must be configured to use that location.

host MVC app inside a website

I have a website (not a web application- in visual studio you get two options-create a website/project) running on IIS 6.0. Now I want to develop few features in MVC architecture.
So I created one MVC application in visual studio and everything is working fine on localhost as a separate application. Now I want to host this MVC app also inside the website I have already deployed.
I created a virtual directory(MVCDir) inside the default website in IIS 6.0. The global.asax file which was in root folder I added the routing function-
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.Ignore("{resource}.axd/{*pathInfo}")
routes.Ignore("{resource}.aspx/{*pathInfo}")
routes.MapPageRoute("Default4", "{controller}/{action}/{id}", "~/MVCDir", False, New RouteValueDictionary(New With {.controller = "Home", .action = "Index", .id = Mvc.UrlParameter.Optional}))
End Sub
*** NOTE- If I write routes.ignoreRoute instead of routes,ignore it says- IgnoreRoute is not a member of System.Web.RoutingCollection*
I called this routing function inside application_start function
now when I run domain.com/home/index
How to solve this problem?
it says resource not found
Maybe this is a problem with you child application inheriting configuration from parent. I had a similar problem when trying to put an app under a website.
You'll need to wrap <system.web> in <location> tag with inheritInChildApplications="false"
Example:
<location path="." inheritInChildApplications="false">
<system.web>
<!-- ... -->
</system.web>
</location>
Here you have more detailed explanation.

attribute does not seem to act at all

I am having problems using the [HandleError] attribute on my Controller Actions - it doesn't seem to work at all (i.e. it doesn't matter if the filter is there or not - I get the same results...). When an Exception is thrown, I get the standard red-toned Server Error in '/' Application error page instead of my custom view.
I have found a couple of other threads on the subject here on SO, and in most cases it seems that setting the customErrors option to On in web.config solved the problem. It has not for me, so I need to find a different solution.
My controller action:
[HandleError]
public ActionResult Index()
{
throw new Exception("oops...");
return View();
}
In my web.config file
<customErrors mode="On"></customErrors>
I have made sure that the Error.aspx file is in the Shared directory, too. What am I missing?
I am running ASP.NET MVC RC Refresh.
Two useful things to know:
By default, HandleError does nothing when running under the development server. The intention is to show developers more useful information:
public virtual void OnException(ExceptionContext filterContext) {
if (filterContext == null) {
throw new ArgumentNullException("filterContext");
}
// If custom errors are disabled, we need to let the normal ASP.NET
// exception handler execute so that the user can see useful
// debugging information.
if (filterContext.ExceptionHandled
|| ! filterContext.HttpContext.IsCustomErrorEnabled) {
return;
}
Note that this case is precisely what customError is supposed to control. If setting customError="On" does not change this behavior:
Check your syntax.
Make sure you're editing the Web.config in the project root, not the one in Views.
Make sure no code sets HttpContext.IsCustomErrorEnabled.
If all else fails, try turning debug off in Web.config
Second, there certain types of errors which HandleError will never handle, notably ASP.NET compilation errors. You don't say which error you're encountering.
You need to specify what page to redirect to as well.
<customErrors mode="On" defaultRedirect="Error.aspx" />
EDIT: Sorry the /Shared/ part should not bet there but you need to tell MVC which page to send the user to with Error.aspx. Then the default route looks for something called Error.aspx in shared.
It was very late! :) I guess that's why someone gave me a minus for the answer! :) At least it works here mate!
I got the same issue and it took me two full days to figure it out finally. It turned out to be that I got an error in Site.Master page, and the Error.aspx used this same master page as all other pages. Obviously the Error.aspx couldn't deal with such situation.
My solution is to create a specific Error.master page that is lightweight and does not include any model data. Additionaly I created a static Error.htm in case an error occurs from Error.aspx. The Web.config setting is as follows:
<customErrors mode="On">
<error statusCode="500" redirect="Error.htm" />
</customErrors>
Hope it helps.
Another reason for this problem may be ,
In Template MVC Application (generated by VS2008 / VS2008 Express) , Error.aspx (generated by VS) uses Master Page.
If Master Page access any ViewData it will throw null reference Exception , then the error.aspx won't be shown.
Use this Simple code as your Error.aspx , it will solve the problem, (along with CustomErrors=On )
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>" %>
<%= Model.Exception.Message %>
To get around the 404 problem when the Error.aspx was supposed to be shown, I had to exclude the Error.aspx from the httpHandler section which prevented any views from being accessed directly (around the mvc 2 framework). I did this by putting Error.aspx in an 'Error' subfolder and putting a web.config in this subfolder with a
<remove path="*" verb="*" />
in the httpHandlers section. My version of this problem (and its solution) may be specific to MVC 2.
Remember to update the defaultRedirect reference, when you move Error.aspx :)
I tried the above suggestions but nothing worked for me. What did the trick was removing this line from my actions within my error controller.
Response.StatusCode = (int)HttpStatusCode.NotFound;
I was pulling my hair out since IIS error messages kept intercepting my error handling. And while its not ideal since I want to provide that status code in my response, I found that removing it prevented IIS 7+ from interfering with my error handling.
DaTribe

Registering custom webcontrol inside mvc view?

I am in the middle of a project where I am migrating some code for a website from WebForms to MVC - unfortunatly there's not enough time to do it all at once, so I will have to do some... not so pretty solutions.
I am though facing a problems with a custom control I have written that inherits from the standard GridView control
namespace Controls {
public class MyGridView : GridView { ... }
}
I have added to the web.config file as usual:
<configuration>
...
<system.web>
...
<pages>
...
<controls>
...
<add tagPrefix="Xui" namespace="Controls"/>
</controls>
</pages>
</system.web>
</configuration>
Then on the MVC View:
<Xui:MyGridView ID="GridView1" runat="server" ...>...</Xui:MyGgridView>
However I am getting a parser error stating that the control cannot be found. I am suspecting this has to do with the mix up of MVC and WebForms, however I am/was under the impression that such mixup should be possible, is there any kind of tweak for this? I realise this solution is far from ideal, however there's no time to "do the right thing".
Thanks
Edit:
I forgot to add that I have already tried to use that as well, with the same result.
Also I will unfortunatly need to use it on several pages, so adding it to the web.config would be the ideal solution, however if there is a solution that just works on individual pages, then that would be more than acceptable as well.
Can't you use the <%# Register %> directive directly in the view? Why do it in web.config, if it is not going to be used throughout the application? I'm not sure if it would work, as I haven't spent much time with ASP.NET MVC, but you can try.

Resources