Using MVC routing to address multi-tenant Azure applications

by Rok Bermež 11. October 2010 10:29
Currently I have a scenario where I have to have more than one site and multiple domains/subdomains in a single Windows Azure web role. For obvious reasons Windows Azure give us FQDN (like myapp.cloudapp.net) instead of IP address so we have to use CNAME to point to our instance/s. The only problem with this approach is that only domain name cannot have CNAME record. For instance www.mydomain.org is fine, but just mydomain.org is not since it needs specific IP address. For the time being this was solved by pointing it to some specific address which would redirect the user to www of that domain. That part was simple and straightforward, but now we need something inside our web role, that would detect requested domain and serve appropriate content. There are a couple of threads online that deal with the issue of addressing multi-tenant application in Windows Azure and most of them deal with url rewriting on the single domain. You can read more about it here and here. In my project I used MVC Areas to separate different sites so all I needed was MVC routing to use domain name from incoming request in its routing configuration. I found an excellent article on the subject here, but unfortunately it was written before MVC 2 introduced areas, so in order to use it lets add area support to it. First lets download the sample here, open and if needed convert solution and open DomainRoute.cs. We only need to add one line to the end of GetRouteData method: if (Defaults.Keys.Contains("area")) data.DataTokens.Add("area", Defaults["area"]); so that it looks like: if (DataTokens != null) { foreach (var token in DataTokens) { data.DataTokens.Add(token.Key, token.Value); } } if (Defaults.Keys.Contains("area")) data.DataTokens.Add("area", Defaults["area"]); } return data; }   And we are ready to register our areas as their own domains/subdomains public override void RegisterArea(AreaRegistrationContext context) { context.Routes.Add("subodomain_default", new DomainRoute( "subdomain.mydomain.si", "{controller}/{action}/{id}", new { area = AreaName, controller = "Home", action = "Index", id = UrlParameter.Optional } ) { DataTokens = new RouteValueDictionary(new { Namespaces = new string[] { "MvcWebRole1.Areas.subdomain.Controllers" } }) } ); }  I strongly suggest you pass Namspaces to every route registration so you can have multiple controllers with the same name serving different tenants. Soon Ill add a DomainRouteExtension and post it here so the usage will be even simpler.

Tags:

.Net | Azure | Web

RadEditor MVC Helper Sample

by Rok Bermež 8. September 2010 15:09
I was asked for RadEditor MVC helper, so here it goes (copy paste code out) : public static MvcHtmlString RadEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class { return RadEditorFor(htmlHelper, expression, ((IDictionary<string, object>)null)); } public static MvcHtmlString RadEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) where TModel : class { return RadEditorFor(htmlHelper, expression, new RouteValueDictionary(htmlAttributes)); } public static MvcHtmlString RadEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes) where TModel : class { string name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText((LambdaExpression)expression)); TProperty value = ExpressionHelper2.GetValue(htmlHelper, expression); return RadEditor(htmlHelper, name, value, htmlAttributes); } public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name) { return RadEditor(htmlHelper, name, null); } public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name, object value) { return RadEditor(htmlHelper, name, null, ((IDictionary<string, object>)null)); } public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes) { return RadEditor(htmlHelper, name, value, new RouteValueDictionary(htmlAttributes)); } public static MvcHtmlString RadEditor(this HtmlHelper htmlHelper, string name, object value, IDictionary<string, object> htmlAttributes) { if (String.IsNullOrEmpty(name)) { name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); if (string.IsNullOrEmpty(name)) { throw new ArgumentException("name"); } } if (htmlAttributes == null) htmlAttributes = new Dictionary<string, object>(); Page page = new Page(); RadMvcScriptManager mvcScriptManager = new RadMvcScriptManager(); mvcScriptManager.EnableViewState = false; page.Controls.Add(mvcScriptManager); RadStyleSheetManager radStyleSheetManager = new RadStyleSheetManager(); page.Controls.Add(radStyleSheetManager); //string id = name.Replace(".", "_"); RadEditor radEditor = new RadEditor(); radEditor.ID = name + "_radeditor"; radEditor.ClientIDMode = ClientIDMode.Static; radEditor.ImageManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName; radEditor.ImageManager.MaxUploadFileSize = 3000000; radEditor.ImageManager.ViewPaths = new string[] { "uploaded/images" }; radEditor.ImageManager.UploadPaths = new string[] { "uploaded/images" }; radEditor.ImageManager.DeletePaths = new string[] { "uploaded/images" }; radEditor.DocumentManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName; radEditor.DocumentManager.MaxUploadFileSize = 20000000; radEditor.DocumentManager.ViewPaths = new string[] { "uploaded/documents" }; radEditor.DocumentManager.UploadPaths = new string[] { "uploaded/documents" }; radEditor.DocumentManager.DeletePaths = new string[] { "uploaded/documents" }; radEditor.MediaManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName; radEditor.MediaManager.MaxUploadFileSize = 50000000; radEditor.MediaManager.ViewPaths = new string[] { "uploaded/media" }; radEditor.MediaManager.UploadPaths = new string[] { "uploaded/media" }; radEditor.MediaManager.DeletePaths = new string[] { "uploaded/media" }; radEditor.FlashManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName; radEditor.FlashManager.MaxUploadFileSize = 50000000; radEditor.FlashManager.ViewPaths = new string[] { "uploaded/flash" }; radEditor.FlashManager.UploadPaths = new string[] { "uploaded/flash" }; radEditor.FlashManager.DeletePaths = new string[] { "uploaded/flash" }; //radEditor.TemplateManager.ContentProviderTypeName = typeof(AzureStorageFileBrowserContentProvider).AssemblyQualifiedName; radEditor.TemplateManager.MaxUploadFileSize = 500000; radEditor.TemplateManager.ViewPaths = new string[] { "~/content/templates" }; radEditor.NewLineBr = false; radEditor.Skin = "Vista"; //radEditor.ToolsFile = "~/Content/administracija/EditorToolbar.xml"; if (htmlAttributes.ContainsKey("ToolsFile")) radEditor.ToolsFile = htmlAttributes["ToolsFile"] as string; UIHintControlParameterDataAnnotationsModelMetadata mmd = (UIHintControlParameterDataAnnotationsModelMetadata)htmlHelper.ViewData.ModelMetadata; if (mmd.TemplateControlParameterExist("ToolBar")) { radEditor.ToolsFile = mmd.GetTemplateControlParameter<string>("ToolBar"); } if (mmd.TemplateControlParameterExist("DisableHtmlFormating") && mmd.GetTemplateControlParameter<bool>("DisableHtmlFormating")) { radEditor.StripFormattingOptions = EditorStripFormattingOptions.None; radEditor.DisableFilter(Telerik.Web.UI.EditorFilters.ConvertToXhtml); } if (value != null) radEditor.Content = value as string; radEditor.DialogHandlerUrl = "/Telerik.Web.UI.DialogHandler.axd"; page.Controls.Add(radEditor); StringWriter output = new StringWriter(); HttpContext.Current.Server.Execute(page, output, false); return MvcHtmlString.Create(htmlHelper.Hidden("", "ToBeReplaced").ToString() + output.ToString()); }

Tags:

.Net | c# | Web

Telerik ASP.NET AJAX Controls in MVC project Part ||

by Rok Bermež 3. September 2010 15:09
Telerik Reporting used in ASP.NET MVC [More]

Tags:

.Net | c# | ASP.NET | Web

Telerik ASP.NET AJAX Controls in MVC project

by Rok Bermež 18. August 2010 14:37
If we want to use Telerik ASP.NET AJAX controls in MVC project, we must also use either ScriptManager or RadScriptManager. But since neither works very well here is more MVC friendly solution: public class RadMvcScriptManager : RadScriptManager { static string JavaScriptBlockFormat = @"<script type=""text/javascript"">//<![CDATA[ {0}//]]></script>"; protected override void Render(HtmlTextWriter writer) { foreach (RegisteredScript script in GetRegisteredClientScriptBlocks()) { if (HttpContext.Current.Items[script.Key] == null) { HttpContext.Current.Items[script.Key] = true; if (script.ScriptType == RegisteredScriptType.ClientScriptInclude) { writer.WriteLine(String.Format(@"<script type=""text/javascript"" src=""{0}""></script>", HttpUtility.HtmlEncode(script.Url))); } } } if (HttpContext.Current.Items["AppInitialize"] == null) { Page.Items["AppInitialize"] = true; writer.WriteLine( String.Format( JavaScriptBlockFormat, @"if(typeof(Sys) != ""undefined""){ $addHandler(window, ""load"", function(){Sys.Application.initialize();}); } else { throw new Error(""Microsoft ASP.NET AJAX cannot be initialized!"")}")); } StringBuilder builder = new StringBuilder(); if (HasReflectionPermission()) { SerializeScriptsForScriptControls(Page, builder); } string scriptContent = builder.ToString(); if (!String.IsNullOrEmpty(scriptContent)) { writer.WriteLine(String.Format( JavaScriptBlockFormat, String.Format("Sys.Application.add_init(function(){{{0}}});", scriptContent))); } } internal void SerializeScriptsForScriptControls(Control control, StringBuilder builder) { if (control is IScriptControl && control.Visible) { IEnumerable<ScriptDescriptor> descriptors = ((IScriptControl)control).GetScriptDescriptors(); if (descriptors != null) { foreach (ScriptDescriptor descriptor in descriptors) { SerializeScriptControlDescriptor(descriptor, builder); } } } if (control.HasControls()) { foreach (Control child in control.Controls) { SerializeScriptsForScriptControls(child, builder); } } } internal void SerializeScriptControlDescriptor(ScriptDescriptor descriptor, StringBuilder builder) { MethodInfo getScriptInfo = descriptor.GetType().GetMethod( "GetScript", BindingFlags.Instance | BindingFlags.NonPublic); if (getScriptInfo != null) { string script = (string)getScriptInfo.Invoke(descriptor, new object[] { }); builder.AppendLine(script); } } internal static bool HasReflectionPermission() { try { new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand(); return true; } catch (SecurityException) { return false; } } }

Tags:

.Net | c# | Web

Handy jQuery developer plugins

by Rok Bermež 6. July 2010 12:32
I've commited a new plugin to my open source repository at Google Code – Niftyscripts. Currently, I' [More]

Tags: , , ,

Development | Web

Calendar

<<  June 2018  >>
MonTueWedThuFriSatSun
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

View posts in large calendar

Page List

Month List