Swap between MVC routing and Durandal routing - asp.net-mvc

Long story short: We're trying to set up Durandal SPA in our pre-existing ASP.NET MVC website. What's we're going for is the ability to hide the SPA behind a feature flag, to where we can enable the SPA flag and have our website adjust accordingly.
We have that portion of it working. However, what we had to do is prefix all of our routes with "/app#" and then tack on the controller/action. For example, "Index" would become "app#Index" in the URL. Durandal routing works just fine with this approach - it pulls the necessary views into place.
What we would like is to use the same routes instead of prefixing each one with "app#" - essentially use Durandal routing when the SPA flag is enabled, otherwise use normal MVC routing, but keep the routes the same.
Any suggestions?

If you know about modules requires convention of the Durandal, will be very simple to understand, you just need to insert this configuration in the Web.config:
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" />
<add name="HtmlFileToMvcHandler" path="App/views/*/*.html" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
Observe that i created the handler "HtmlFileToMvcHandler" with this pattern "App/views/*/*.html" i used that pattern because my CRUD convention, and with this i told to the MVC handler that all of the requests that comes with this pattern will be handled. But now you need handle the requests that will came. So you can use the RouteAttribute like this:
[Route("App/View/Home/index.html")]
public ActionResult Index()
{
return View();
}
or map that route in the route config like this:
routes.MapRoute("Name",
"App/views/{controller}/{action}.html");
My english will be better in the next time XD

Related

ASP.Net MVC4 Routing not working - reserved word?

In short, I have an MVC web app that has a proxy class to marshall requests to another web app under the context of the logged in user.
This all works fine except that some of the outgoing links (i.e. inbound links to my MVC app) from the other web app contain the url "/views".
These requests should be mapped according to this route:
routes.MapRoute(
name: "TableauViews",
url: "views",
defaults: new { controller = "Tableau", action = "Views" }
);
But it never happens. If I change the name of the controller action to something else and enter the corresponding url in a browser, it works.
This leads me to suspect that there is some problem mapping a url containing the word "views" as part of its path. Can anyone confirm this?
The issue is the order of operations. Views is a physical folder and a route. The ASP.NET HttpHandler will read the web.config and block anything going to views before the route handler picks up the URL. If you look at the web.config file in your views folder (where your views are actually stored) you will likely see something like this:
<httpHandlers>
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
Also, later in the config there may also be this:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
This is your culprit. I would suggest either naming your route something more like "externalViews" or simply "external" might help. The other alternative is to remove the line above from your views web.config, but this could result in some undesirable behavior.
This article deals with restricting only certain types of files from being delivered instead of blocking all that may be helpful for you.
http://blog.falafel.com/Blogs/j-tower/2014/03/28/loading-javascript-files-from-the-views-folder-in-asp-net-mvc
I couldn't find anything specifically saying "views" is a reserved word, but the article http://haacked.com/archive/2010/04/29/allowing-reserved-filenames-in-URLs.aspx describes how to relax the rules on what words can be used.

prevent Authentification for specific route

I have a MVC Webapplication. It uses Forms auhtentification.
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="90" />
</authentication>
How can i bypass this for a single route, like xyz.com/us/ht/ht?
I want to bypass the whole functionality to prevent getting aspxanonymous cookies and i dont want entries in the membership db for this route.
If you are using MVC4 just add the [AllowAnonymous] tag to your controller action.
Otherwise do it in your web.config like this
<configuration>
<location path="route/thatanon/isallowed">
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>
</configuration>
One way to solve this is to use a custom AnonymousIdentificationModule for the route /us/ht/ht/.
The stuff is handled here ->
System.Web.Security.AnonymousIdetificationModule

MVC Route to Action for Javascript file

I am trying to add a mvc route to generate a javascript from the controller. I have added the following route and it doesn't work:
routes.MapRouteWithName(
"DataSourceJS", // Route name
"Scripts/Entities/{controller}/datasource.js", // URL with parameters
new { controller = "Home", action = "DataSourceJS"} // Parameter defaults,
, null
);
But if I change the route to not have the ".js" and I navigate to "Scripts/Entities/{controller}/datasource" it works. But I need to have the .js file extension on there, how do I make this work?
how do I make this work?
IIS intercepts the request because it contains a file extension and hijacks it thinking it is a static file and not passing it to your application.
To make it work you should tell IIS not to do that. Inside the <system.webServer> section you could add the following handler to indicate that requests with the specified pattern should be handled by the managed pipeline:
<system.webServer>
<handlers>
...
<add name="ScriptsHandler" path="Scripts/Entities/*/datasource.js" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Some people might also tell you to use:
<modules runAllManagedModulesForAllRequests="true" />
but I wouldn't recommend you doing that because this means that all requests to static resources will now be flowing through the managed pipeline which could have a negative performance overhead for your application. The handler syntax allows you to selectively enable this only for certain route patterns and HTTP verbs.

Login page in MVC3 application - Login function can't be found

I am trying to create my own form-authentication view in MVC application, but my site appear not to find the Login function.
I first tried to create a regulr view, and call the function using ajax, but it didn't work, so I tried to use form and submit as following:
<form method="post" action="~/Login/Login_btnClick">
<input type="submit" name="Login" value="Login" />
of course I also declared in the web config it's form authentication, and set the login page to be the link:
<authentication mode="Forms">
<forms loginUrl="~/Login/Login" defaultUrl="~/Home/index" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
I also used locations so my javascripts and css files will be found. As I got the
Failed to load resource: the server responded with a status of 400 (Bad Request)
error, I tried to add also the Controllers folder to locations:
<location path="Controllers">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
But it still got me the same error....
Any idea what might solve my problem ?
Thanks
You should create a corresponding controller action that will handle the form submission. So for example if you have the following form:
<form method="post" action="/Login/LogOn">
<input type="submit" name="Login" value="Login" />
</form>
then you should create a LogOn action on your Login controller:
[HttpPost]
public ActionResult LogOn()
{
...
}
Also the snippet you have shown from your web.config in which you are disabling access to the Controllers folder is absolutely unnecessary. In ASP.NET MVC controllers are compiled and when you deploy your application such folder doesn't exist at all.
In addition to that authorization in ASP.NET MVC is controlled with the [Authorize] attribute, not in web.config using the <authorization> tag. So for example if you want to protect a certain controller action from being accessible only to authenticated users you simply decorate it with this attribute:
[Authorize]
public ActionResult Index()
{
...
}
Here are some tutorials on the ASP.NET MVC site which illustrate how you could implement authentication and authorization in an MVC application.
Also when you create a new ASP.NET MVC 3 application using the Internet Template there's already an AccountController created for you as well as the corresponding views. You could play with this out-of-the-box template to better understand the concepts.
Thanks, I got the solution....
I should have done 2 things:
1. Change the
<deny users="?" />
to:
<allow users="?" />
change in my form the action so it should be: #Url.Action("MyLoginFunc", "MyLoginController")

Multiple AppSettings.config files in a hierarchy

I have a question that has struck me a couple of times when creating ASP.Net MVC applications: Say you have one application that you want to deploy to multiple customers. The application code is identical, but you want to be able to have one appSettings.config file for each customer, so that you are able to deploy to different customers by just changing the configSource of the appSettings tag in web.config ( a bit simplified, but still).
Then you realize that 50% of the content in appSettings.config is common for all customers, and only 50% is customer dependent. What you may end up doing is having duplicated entries in all the appSettings files, which is a major pitfall as you then need to remember to update all of them if you want to do an application-wide change to the config.
In a case like this I would really like to have some sort of hierarchical system where you are able to have a "base config" and a "customer config" in separate files. Then I would like the ConfigurationManager to first check for a value in the customer config, and if it is not defined there it will go to the base config instead.
I haven't found a straight-forward way of solving this with the out-of-the-box functionality in ASP.Net MVC4. Does it exits, or do I need to work my way around the default ConfigurationManager class somehow? I could potentially create my own class and replace all calls to ConfigurationManager.AppSettings[key] with a call to my own implementation, but I'd rather avoid that if I could. I want to be able to take use of some of the basic functionality that the built-in ConfigurationManager takes care of, like caching, etc.
Anyone who has solved a similar problem like this before? I keep thinking that it seems like a common scenario..
It is a common scenario, and there are different ways to solve it. One way would be to use config transforms. You could have a Web.Customer1.config, Web.Customer2.config, etc, just like you have Web.Debug.config and Web.Release.config. In the customer-specific transform files, you could "override" only the appSettings that your customer wants to customize.
To create the different transforms, first create different project platforms. Go to the Visual Studio Configuration Manager, and in the Configuration column for your web project (or any project that needs customized configuration settings), click the dropdown and then click <New...>. Name the New Project Configuration Customer1 or whatever you want, check the box for Copy settings from, and pick Release from that dropdown. Also check the Create new solution configurations checkbox.
Finally, right click your web.config file and click Add config transform. This will generate a template Web.Customer1.config file for you. Edit it to override the appSettings it needs to, using the xdt: config transform attributes. Then you can publish the project using the Customer1 solution build configuration. As part of the build, the web.config will be transformed and you will end up with a different web.config file for each customer. You can also use this to customize projects for different deployments, i.e. changing db connection strings, smtp servers, literally anything in the XML configuration file.
As a last thought, make sure you right click each Web.Xyx.config file, choose properties, and set its Build Action to None.
Example:
base web.config
<appSettings>
<add key="CommonProperty1" value="[for all customers]" />
<add key="CommonProperty2" value="[for all customers]" />
<add key="CommonProperty3" value="[for all customers]" />
<add key="CustomProperty1" value="[for one customer]" />
<add key="CustomProperty2" value="[for one customer]" />
<add key="CustomProperty3" value="[for one customer]" />
<appSettings>
web.Customer1.config
<appSettings>
<add key="CustomProperty1" value="The Ohio State University" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<add key="CustomProperty2" value="Scarlet" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<add key="CustomProperty3" value="Gray" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<appSettings>
web.Customer2.config
<appSettings>
<add key="CustomProperty1" value="Michigan University" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<add key="CustomProperty2" value="Blue" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<add key="CustomProperty3" value="Maize" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<appSettings>

Resources