ASP.NET MVC add/remove IIS app name/alias from URL dynamically - ajax

Because of the IIS 6.1 settings, every app that's being deployed has an alias and that has an impact on the URL. In Visual Studio's development server, the URL looks like this:
http://localhost:27019/controller/action
But after being deployed to IIS:
http://servername/appname/controller/action
as you can see there is an appname added to the URL. All the Ajax calls become incorrect after deployment. I have to create an isIIS variable and manually assign a value to it in order to make it work:
var isIIS = true; // set to false if runs locally;
window.appAlias = (isIIS) ? '/'+window.location.href.split('/')[3] : '';
And in my Ajax call:
$.post( window.appAlias + webUrl, {} , callback );
same thing with GET calls, I have to prepend the window.appAlias. Is there a way to dynamically detect whether the server is IIS or Visual Studio Development Server? I understand the #Uri.Content("~/controller/action") but I am not writing my JavaScript on the Razor view.
I am using Visual Studio 2012, target framework .NET 4.5, MVC 4 and jQuery 1.9.2 for development. The IIS application pool has .NET 4.0.
Edit
Here is my temporary solution: to add global values in _Layout.cshtml:
Object.assign({
action1: '#Url.Content("~/controller/action1")',
action2: '#Url.Content("~/controller/action2")'
}, window);

Related

Error with Asp.net MVC3 app after loading into Visual Studio 2012

I opened an existing ASP.NET MVC3 project that formerly worked just fine in a newly built machine with Visual Studio 2012 installed.
I'm now getting null exceptions in the following code. After a User logs in, the following code is then executed to perform page fragment-level access.
The null exception is thrown on the WebViewPage.User object. However, when in debug mode, I can actually inspect a real instance of the object (see image below)
public static class WebViewPageExtensions
{
public static bool HasAccess(this WebViewPage pg)
{
if (pg == null) throw new ArgumentNullException("WebViewPage is null");
if (pg.User == null) throw new ArgumentNullException("WebViewPage User is null");
return pg.User.IsInRole(User.ACCESS_LEVEL_A) || pg.User.IsInRole(User.ACCESS_LEVEL_B);
}
}
Note: this could be something with the way my environment is configured (web.config maybe?), but not really sure where to start. As it is, the code that this is happening on is the same code running in production and the former developer environment.
All the references are still referring to the ASP.NET MVC3 version of the framework running on the .NET 4.0 platform.
EDIT: Here's the callilng code from a Razer view:
#if (this.HasAccess()) {
<div>
HTML here
</div>
}
Any thoughts?
Please read section "Installing ASP.NET MVC 4 breaks ASP.NET MVC 3 RTM applications" from link http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253815. Follow setps "Required updates" to update your MVC 3 app. If you havent noticed, MVC4 gets installed with VS2012 and this is documented behavior.

CRM 2011 external content with relative URL

In CRM 4.0 we could place dynamic content (aspx) in the ISV-folder in CRM, creating separate applications but with security and relative URLs to CRM, so for example a custom 360 view of account could be linked in an iframe using a relative URL along the lines of
/ISV/CrmMvcApp/Account.aspx/Overview?id=....
In CRM 2011 usage of the ISV folder is deprecated and Microsoft has some guidelines on how to transition into doing this in supported manner (MSDN gg309571: Upgrade Code in the ISV folder to Microsoft Dynamics CRM 2011). They say:
For scenarios that will not be satisfied by the Web resources feature, create your Web application in its own application pool with its own web.config.
The way I am reading this (coupled with the guidelines on supported/unsupported) is that we need a separate web site in IIS with its own binding as you are not allowed to add virtual directories etc. under the standard CRM app. This is unfortunate and does not allow relative paths/URLs in customizations and sitemap. This is troublesome especially when exporting and importing solutions from DEV, TEST and/or PROD.
Are my assumptions wrong?
Can we somehow have relative paths?
Have anyone else found a pragmatic and easy approach to having external content without doing the sitemap and customization changes for each environment?
EDIT: Confirmed with other sources that my understanding of the guidelines are correct, as this is also listed in the list of unsupported changes. Virtual folders and web apps are to be kept totally separated from the default CRM web site.
Creating an Internet Information Services (IIS) application inside the Microsoft Dynamics CRM website for any VDir and specifically within the ISV folder is not supported.
MSDN gg328350: Unsupported Customizations
If you primarily need to access CRM data/records, take a look at using a jScript web resources. You can do "most" CRUD operations using the REST OData services. If you use JQuery to parse the JSON it's very productive.
I have found a solution much like the javascript redirect, without the need for client execution and only configuring the environment details (servername, port) once. Additional logic can easily be added.
The solution creates a dependency into the customizations, but not an environment one like and can be used for unmanaged and managed solutions.
The solution was to place a file Redirect.aspx in the ISV folder. The code does not in any way interact with CRM and falls within the supported guidelines, however the solution is not future proof as the ISV folder is deprecated by Microsoft.
Redirect.aspxwill automatically pass along any parameter passed, so will work with or without the entity identifiers and so on.
Usage:
Place the file in the ISV folder on the CRM app server
Change the server name and port to match the current environment (must be done for each environment)
In customizations, for example for an iframe, use the following as a source:
/ISV/Redirect.aspx?redirect=http://SERVERREPLACE/CustomMvcApp/SomeControllerAction
Here is the content of Redirect.aspx
<%# Page Language="C#" %>
<html>
<script runat="server">
protected override void OnLoad(EventArgs e)
{
// must be customized for each environment
const string ServerBaseName = "appserver1:60001";
const string UrlParameterName = "redirect";
const string ReplacePattern = "SERVERREPLACE";
var parameterUrl = Request.Params[UrlParameterName].Replace(ReplacePattern, ServerBaseName);
var queryStringBuilder = new StringBuilder();
foreach (var key in Request.QueryString.AllKeys)
{
if (key == UrlParameterName)
{
continue;
}
queryStringBuilder.Append(!(queryStringBuilder.Length > 0) ? "?" : "&");
queryStringBuilder.Append(key + "=" + Request.QueryString[key]);
}
var completeRedirectString = parameterUrl + queryStringBuilder;
Response.Redirect(completeRedirectString);
}
</script>
<head>
<title>Redirecting</title>
</head>
</html>
Not quite "relative urls" as per your question, but a solution I use is to store "stub" or "root" urls in a config entity and read those records in JScript at runtime to determine the fully qualified destination for your custom links.

IIS 5.1 + ASP .NET MVC 3 + Image not loaded

I am developping a web application by using the ASP .NET MVC 3 framework.
I am using Windows XP Professional on my computer.
I have decided to execute my web application via my IIS 5.1 local server during the development.
First I have installed IIS 5.1.
Then I have created a virtual directory under the default web site for my web application.
Then I have executed the following command line :
aspnet_regiis -i
Then I have added the following extension mapping to my virtual directory :
Executable : C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll
Extension : .*
Option "Check file existence" unchecked.
For information here is my RegisterRoutes method written in my Global.asax.cs file :
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Accueil", action = "Accueil", id = UrlParameter.Optional } // Default parameters
);
}
When I launch my web application via Visual Studio 2010 in debug mode then I can load one my view with success.
But I noticed that an image was not loaded.
Here is the img tag containing the image :
<img src="../../../Content/images/Valider_064.png" alt="Valider" />
Here is a piece of my web application folder tree :
ActivitesHtml5 [FOLDER] : Root of web application
Content [FOLDER]
images [FOLDER]
Valider_064.png [FILE]
Controller [FOLDER]
ConnexionController.cs [FILE] : Contains the action method to generate my view.
Views [FOLDER]
Connexion [FOLDER]
Connexion [FOLDER]
Connexion.cshtml [FILE] : Razor file of my view.
Does someone know why my image is not correctly loaded ?
How about using url helpers instead of hardcoding your urls:
<img src="#Url.Content("~/Content/images/Valider_064.png")" alt="Valider" />
Also I would totally recommend you to stay away from IIS 5.1 especially if your target deployment server for the application will be IIS 7.0+. Cassini or IIS Express are much better alternatives and are directly integrated into Visual Studio.

MVC Site versus Virtual Application Routing

We use TFS to deploy our applications to multiple environments (Dev, QA, Prod). Simple enough, our Dev and QA environments have URLS like dev.domain/APPLICATION and qa.domain/APPLICATION. So we have a single site with each application as a virtual application.
However in production, they want each application to be its own site, such as APPLICATION.domain.com... Grrr! In Visual Studio, the application's properties is configured to be in a "Virtual Path". I"m not sure how I should go about this issue. The appliation contains code such as: <a href='/APPLICATION/File/Download?id=<#= PkFileId #>'><#= Name #></a> which causes problems in production since its not in a virtual application.
I could make a site called application.domain.com with an empty directory. Then add a Virtual Application, but then I would have to put a redirect in the root of the site to go to the virtual application. Or perhaps I can somehow configure the application? Not sure what my options are... Any suggestions are appreciated!
The appliation contains code such as:
<a href='/APPLICATION/File/Download?id=<#= PkFileId #>'><#= Name #></a>
ASP.NET MVC applications should not contain code like that (a code in which urls are hardcoded). In ASP.NET MVC applications you should always use HTML and Url helpers:
#Html.ActionLink(
Model.Name,
"Download",
"File",
new { id = Model.PkFileId },
null
)
This way it is certain that no matter how your routes are configured or under which virtual directory your application is hosted, it should work.
UPDATE:
After your comment it looks like you are using the Telerik Grid. In this case you may try something along the lines to generate proper anchors:
columns
.Bound(x => x.PkFileId)
.ClientTemplate(
Html.ActionLink(
"<#= Name #>",
"Download",
"File",
new { id = "<#= PkFileId #>" },
null
).ToString()
)
.Title("");

Deploying Asp.Net MVC 2 /C# 4.0 application on IIS 6

I got a problem migrating from VS.Net 2008 / MVC 1 to VS.NET 2010 (+C# 4.0) / MVC 2
The web.config has been updated, the site runs well in Cassini, but my problem now is deploying on IIS 6.
I updated the web site to run using ASP.Net 4,
but whatever URL I try, I always have a 404 error. It's as if the routing was not taken into account (yes, the wildcard mapping has been done).
I do not understand this mess and could not google anything interesting...
Thanks for your suggestions !
Ok I got y answer (thanks to a colleague)
When migrating from ASP.Net 2.0 to ASP.Net4.0,
if you meet the same problem,
then check in Web Service Extension if ASP.Net v4 is Allowed.
In my case, after installing the .Net framework 4, it was prohibited.
Will & Mark : thanks for your help, hope it will helps others.
I think I know what's happening: on IIS6, as well as the wildcard mapping you will need a default document (Default.aspx) that routes folder requests to the MVC handler.
There was one included with the MVC1 project templates, but it has been removed in MVC2.
Default.aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="YourNameSpace._Default" %>
<%-- Please do not delete this file. It is used to ensure that ASP.NET MVC is activated by IIS when a user makes a "/" request to the server. --%>
and Default.aspx.cs:
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
namespace YourNameSpace
{
public partial class _Default : Page
{
public void Page_Load(object sender, System.EventArgs e)
{
// Change the current path so that the Routing handler can correctly interpret
// the request, then restore the original path so that the OutputCache module
// can correctly process the response (if caching is enabled).
string originalPath = Request.Path;
HttpContext.Current.RewritePath(Request.ApplicationPath, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext.Current);
HttpContext.Current.RewritePath(originalPath, false);
}
}
}
When you say "It's as if the routing was not taken into account", I suspect that it actually isn't, and this is your problem.
This finally fixed it for me:
I commented earlier, and a wee bit prematurely. My comment to Mark B's post was getting my initial Index view to show up, but then I kept getting the 404 errors whenever I navigated to any other view.
I was also distracted by the green check mark approved solution in this particular forum, but I could not even see the web server extensions folder in IIS 6 on my desktop; therefore, I had no control from that stand point of enabling aspnet 4.0, though I made sure it was installed by performing running the following command line:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319> aspnet_regiis -i
Now for the actual piece that finally allowed me to navigate to the other views besides just my Home/Index:
In the Global.asax.cs file of your VS 2010 Solution, you will see code as follows in the RegisterRoutes method:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
I simply added ".aspx" after the {action} section of the tag as follows:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}.aspx/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
And ahla wahla Peanut Butter and Jelly sandwiches. :0)
If you want to do it in C#, just add the System.DirectoryServices reference and this piece should do the job nicely.
DirectoryEntry w3svc = new DirectoryEntry("IIS://localhost/W3SVC");
w3svc.Invoke("EnableWebServiceExtension", "ASP.NET v4.0.30319");
w3svc.CommitChanges();
HTH

Resources