<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MVC Archives - Blog IT</title>
	<atom:link href="https://blogit.create.pt/category/development/mvc/feed/" rel="self" type="application/rss+xml" />
	<link>https://blogit.create.pt/category/development/mvc/</link>
	<description>Create IT blogger community</description>
	<lastBuildDate>Thu, 10 Jan 2019 12:46:25 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
	<item>
		<title>Remote resource handling in a MVC website project</title>
		<link>https://blogit.create.pt/andresantos/2016/04/15/remote-resource-handling-in-a-mvc-website-project/</link>
					<comments>https://blogit.create.pt/andresantos/2016/04/15/remote-resource-handling-in-a-mvc-website-project/#comments</comments>
		
		<dc:creator><![CDATA[André Santos]]></dc:creator>
		<pubDate>Fri, 15 Apr 2016 18:01:43 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[action filter]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[mvc 5]]></category>
		<category><![CDATA[resources]]></category>
		<category><![CDATA[resx]]></category>
		<category><![CDATA[viewmodel]]></category>
		<category><![CDATA[visual studio]]></category>
		<category><![CDATA[webapi]]></category>
		<guid isPermaLink="false">http://blogit.create.pt/andresantos/?p=1381</guid>

					<description><![CDATA[<p>I don&#8217;t have very fond memories of using .Net resource files (.resx) to handle the translation of static web page elements such as form labels. The Visual Studio resx editor was slow and using it to change resources that were more than a single line of text was a pain. I still have nightmares where [&#8230;]</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2016/04/15/remote-resource-handling-in-a-mvc-website-project/">Remote resource handling in a MVC website project</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I don&#8217;t have very fond memories of using .Net resource files (.resx) to handle the translation of static web page elements such as form labels.</p>
<p>The Visual Studio <em>resx</em> editor was slow and using it to change resources that were more than a single line of text was a pain. I still have nightmares where I&#8217;m trying to edit complete email templates on a single field of a <em>resx</em> file&#8230;</p>
<p>The biggest problem with resource files, however, is that they are included in the project. This creates a problem for both the developers and the content managers, since the content managers are not able to change resources themselves, and the developers need to be changing resources files when they could be doing something productive.</p>
<p>The following will show a way to handle resource items in a MVC website project, where the resources can be stored wherever they are more easily handled by content managers: a SharePoint list, a database table, an excel file, or something completely different.</p>
<p><span id="more-6480"></span></p>
<p>The process is really simple:</p>
<ol>
<li>Select every resource item key needed to render the current page</li>
<li>Fetch the resources associated with the keys provided at the end of the current action</li>
<li>Populate a ViewModel property with the resource items</li>
<li>Use the resource items in their respective places in the markup</li>
</ol>
<h3>1 &#8211; Compile a list of resource keys</h3>
<p>Typically in a website, there are certain areas of the layout that are common across all pages, the header and the footer being the most prominent candidates. There are, however, other areas that can be reused across a smaller subset of pages such as a common banner in the FAQ pages. Taking this into account, we split the resource keys by groups, where each group (a list of strings) contains every resource key needed for that area and load them on each action, like so:</p>
<pre class="brush: csharp; title: Area resource keys; notranslate">
model.ContentResourceKeys = new List&amp;lt;string&amp;gt;();
model.ContentResourceKeys.AddRange(ResourceHelper.SOCIALNETWORK_RESOURCE_KEYS);
model.ContentResourceKeys.AddRange(ResourceHelper.HOTEL_BANNER_RESOURCE_KEYS);
model.ContentResourceKeys.AddRange(ResourceHelper.DOCUMENTS_RESOURCE_KEYS);
model.ContentResourceKeys.AddRange(ResourceHelper.GENERAL_FOOTER_BANNERS_RESOURCE_KEYS);
model.ContentResourceKeys.AddRange(ResourceHelper.LANDING_PAGE_SEARCH_AREA_RESOURCE_KEYS);
model.ContentResourceKeys.AddRange(ResourceHelper.LANDING_PAGE_MODULES_RESOURCE_KEYS);
</pre>
<p>The ContentResourceKeys property is defined in a <em>MasterModel</em> that is extended by every View Model used across the site, as can be seen here: <a href="http://blogit.create.pt/andresantos/2014/11/07/pre-set-common-viewmodel-preperties-before-action-result/">http://blogit.create.pt/andresantos/2014/11/07/pre-set-common-viewmodel-preperties-before-action-result/</a>. That post also describes the Action Filter that is executed after every action on the site and it&#8217;s the place where we append the footer and header resources to the <strong>ContentResourceKeys</strong> list:</p>
<pre class="brush: csharp; title: Master resouce keys; notranslate">
List&amp;lt;string&amp;gt; resourceKeys = new List&amp;lt;string&amp;gt;();
resourceKeys.AddRange(ResourceHelper.HEADER_RESOURCE_KEYS.ToList());
resourceKeys.AddRange(ResourceHelper.LOGIN_RESOURCE_KEYS.ToList());
resourceKeys.AddRange(ResourceHelper.FOOTER_RESOURCE_KEYS.ToList());
resourceKeys.AddRange(ResourceHelper.LOADING_RESOURCE_KEYS.ToList());
resourceKeys.AddRange(ResourceHelper.HEADER_COOKIES_RESOURCE_KEYS.ToList());

if (model.ContentResourceKeys != null &amp;amp;&amp;amp; model.ContentResourceKeys.Count &amp;gt; 0)
{
    resourceKeys.AddRange(model.ContentResourceKeys);
}
</pre>
<h3>2 &#8211; Fetch the resources</h3>
<p>After compiling the resource keys needed, we go on and fetch the associated resource items. The project where this was implemented used a WebAPI to serve all the page content and the resource items were no exception. So, we send a POST request to the resource WebAPI method and fetch the needed resources, for the user language, from the available backoffice (we used a SharePoint list).</p>
<pre class="brush: csharp; title: Fetch the keys; notranslate">
model.Resources.AddRange(ResourceFacade.ListResources(model.CurrentLanguageCode, resourceKeys));
</pre>
<h3>3 &#8211; Add them to the View Model</h3>
<p>The <em>Resources</em> property available in the View Model where we added the result of the call to the resources WebAPI method is a string Dictionary. Since C# Dictionaries don&#8217;t provide an <em>AddRange</em> method, we create an extension method that enables us to append resources to a dictionary that&#8217;s not empty. Moreover, with this extension method we are able to scrap duplicate keys:</p>
<pre class="brush: csharp; title: Dictionary AddRange extension method; notranslate">
public static class IDictionaryExtensions
{
    public static void AddRange&amp;lt;T, S&amp;gt;(this IDictionary&amp;lt;T, S&amp;gt; source, IDictionary&amp;lt;T, S&amp;gt; collection)
    {
        if (collection == null)
        {
            throw new ArgumentNullException(&quot;Collection is null&quot;);
        }

        foreach (var item in collection)
        {
            if (!source.ContainsKey(item.Key))
            {
                source.Add(item.Key, item.Value);
            }
        }
    }
}
</pre>
<h3>4 &#8211; Use the resources in the views</h3>
<p>Since every View Model extends the MasterModel, we are able to use the same property everywhere:</p>
<pre class="brush: xml; title: Usage in the view; notranslate">
&amp;lt;footer id=&quot;footer&quot;&amp;gt;
  &amp;lt;div class=&quot;container&quot;&amp;gt;
    &amp;lt;div class=&quot;newsletter&quot;&amp;gt;
      &amp;lt;h2&amp;gt;@Model.Resources&#x5B;&quot;Footer.Newsletter.Title&quot;]&amp;lt;/h2&amp;gt;
</pre>
<p>This way, we are able to manage the resource keys in a SharePoint list, or any other backoffice solution.</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2016/04/15/remote-resource-handling-in-a-mvc-website-project/">Remote resource handling in a MVC website project</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blogit.create.pt/andresantos/2016/04/15/remote-resource-handling-in-a-mvc-website-project/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>A Multi-Tenant Website in MVC</title>
		<link>https://blogit.create.pt/andresantos/2015/06/18/a-multi-tenant-website-in-mvc/</link>
					<comments>https://blogit.create.pt/andresantos/2015/06/18/a-multi-tenant-website-in-mvc/#comments</comments>
		
		<dc:creator><![CDATA[André Santos]]></dc:creator>
		<pubDate>Thu, 18 Jun 2015 17:28:18 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[multi-tenancy]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[mvc 5]]></category>
		<category><![CDATA[viewengine]]></category>
		<guid isPermaLink="false">http://blogit.create.pt/andresantos/?p=301</guid>

					<description><![CDATA[<p>In my most recent project we had the need to build multiple websites that would share some common functionalities but would be installed in separate servers and would be available in different domains. We were using .NET 4.5 and MVC 5 and there was no out of the box solution for this problem. Throughout my [&#8230;]</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2015/06/18/a-multi-tenant-website-in-mvc/">A Multi-Tenant Website in MVC</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In my most recent project we had the need to build multiple websites that would share some common functionalities but would be installed in separate servers and would be available in different domains.</p>
<p>We were using .NET 4.5 and MVC 5 and there was no <em>out of the box</em> solution for this problem. Throughout my search I came upon <a title="Setting Up an MVC4 Multi-Tenant Site v1.1" href="http://pt.scribd.com/doc/140181293/Setting-Up-an-MVC4-Multi-Tenant-Site-v1-1" target="_blank" rel="noopener">this</a> paper and we took some ideas from it. This post describes the main changes to a <em>normal</em> website project we had to make in order to make this work.</p>
<p><span id="more-6464"></span></p>
<p>First of all we had to create a <strong>Core</strong> MVC5 project that we set up to be used as a Class Library. We must also reference <em>System.Runtime.Remoting</em>. This Core project contains the shared functionality that is used on each site and as such is referenced by them. This project follows the usual MVC architecture where the only difference is that the views must have the build action set to <strong>embedded resource</strong>. It&#8217;s set to this build action so that the site projects can get them from the Core project assembly upon launch. This is accomplished through a custom view engine that is used on each site:</p>
<pre class="brush: csharp; title: ; notranslate">
public class EmbeddedResourceViewEngine : RazorViewEngine
{
    public EmbeddedResourceViewEngine()
    {
        ViewLocationFormats = new&#x5B;]
        {
            // Code below will search the client before core.
            &quot;~/Views/{1}/{0}.aspx&quot;, &quot;~/Views/{1}/{0}.ascx&quot;, &quot;~/Views/Shared/{0}.aspx&quot;,
            &quot;~/Views/Shared/{0}.ascx&quot;, &quot;~/Views/{1}/{0}.cshtml&quot;,
            &quot;~/Views/{1}/{0}.vbhtml&quot;, &quot;~/Views/Shared/{0}.cshtml&quot;,
            &quot;~/Views/Shared/{0}.vbhtml&quot;, &quot;~/Views/Shared/Partials/{0}.cshtml&quot;,
            &quot;~/Views/Shared/Partials/{0}.vbhtml&quot;, 

            // The embedded view will be copied to a tmp folder
            // using a similar structure to the View Folder
            &quot;~/CoreViews/Views/{1}/{0}.cshtml&quot;,
            &quot;~/CoreViews/Views/Shared/{0}.cshtml&quot;,
            &quot;~/CoreViews/Views/{1}/{0}.vbhtml&quot;
        };

        PartialViewLocationFormats = new&#x5B;]
        {
            &quot;~/Views/Shared/{0}.cshtml&quot;, // Client first
            &quot;~/CoreViews/Views/Shared/{0}.cshtml&quot;,
            &quot;~/Views/Shared/Partials/{0}.cshtml&quot;,
        };

        // Handle all areas generically
        AreaViewLocationFormats = new&#x5B;]
            {
                &quot;~/Areas/{2}/Views/{1}/{0}.cshtml&quot;, 

                // client Specific
                &quot;~/CoreViews/Areas/{2}/Views/{1}/{0}.cshtml&quot;, 

                // Pick up core  if no client
            };

        AreaPartialViewLocationFormats = new&#x5B;]
            {
                &quot;~/Areas/{2}/Views/Shared/{0}.cshtml&quot;, 

                // Client Specific – not used in demo
                &quot;~/CoreViews/Areas/{2}/Views/Shared/{0}.cshtml&quot;

                // Pick up core  if no client
            };

        SaveAllViewsToTempLocation();
    }

    private static void SaveAllViewsToTempLocation()
    {
        IEnumerable&lt;string&gt; resources =
            typeof(EmbeddedResourceViewEngine).Assembly.GetManifestResourceNames()
                .Where(name =&gt; name.EndsWith(&quot;.cshtml&quot;));
        foreach (string res in resources)
        {
            SaveViewToTempLocation(res);
        }
    }

    private static void SaveViewToTempLocation(string res)
    {
        // Get the file path to manipulate and the fileName for re-addition later.
        string&#x5B;] resArray = res.Split('.');

        // rebuild split to get the paths.
        string filePath = string.Join(&quot;/&quot;, resArray, 0, resArray.Count() - 2) + &quot;/&quot;;
        string fileName = string.Join(&quot;.&quot;, resArray, resArray.Count() - 2, 2);

        // replace name of project, with temp file to save to.
        string rootPath = filePath.Replace(&quot;ProjectName&quot;, &quot;~/CoreViews&quot;);

        // Set in line with the server folder...
        rootPath = HttpContext.Current.Server.MapPath(rootPath);
        if (!Directory.Exists(rootPath))
        {
            Directory.CreateDirectory(rootPath);
        }

        // Save the file to the new location.
        string saveToLocation = rootPath + fileName;
        Stream resStream = typeof(EmbeddedResourceViewEngine).Assembly.GetManifestResourceStream(res);

        System.Runtime.Remoting.MetadataServices.MetaData.SaveStreamToFile(resStream, saveToLocation);
    }
}
</pre>
<p>With this Core project in place we can now have multiple website projects that use some common features defined in Controllers, Models, Views or any other custom code, such as custom attributes. We can also redefine Actions for a specific website, or use a different view for each website.</p>
<p>Views and PartialViews defined in the Core project must explicitly inherit from <em>System.Web.Mvc.WebViewPage</em> because they no longer know their base type from the Web.Config.</p>
<p>The project that motivated the use of this solution required the creation of 4 sites. One that contained all functionality (<em>common</em>), and 3 others that only contained an homepage similar to the common site (with one exception). For this reason we created 2 website projects:</p>
<ul>
<li>Common &#8211; Used to create the main site that contains all functionality</li>
<li>Specific &#8211; Used to create 3 sites where only one contains a specific homepage</li>
</ul>
<p>Instead of creating 3 specific website projects we decided to create only one because we can define what type of site it is by configuration when we publish it (using different publish profiles and web.config transforms).</p>
<p>With this setup, the Core project basically contains the Homepage Models,Views and Controller and some other core functionalities. The Common site project contains almost everything, except an homepage which it inherits from the Core project. The specific site project redefines the homepage for 1 of the 3 sites it represents and that also inherit from the Core project.</p>
<p>Without this setup we would have to replicate the homepage and other core functionalities across 4 website projects.</p>
<p>&nbsp;</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2015/06/18/a-multi-tenant-website-in-mvc/">A Multi-Tenant Website in MVC</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blogit.create.pt/andresantos/2015/06/18/a-multi-tenant-website-in-mvc/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Pre-set common viewmodel properties before action result</title>
		<link>https://blogit.create.pt/andresantos/2014/11/07/pre-set-common-viewmodel-preperties-before-action-result/</link>
					<comments>https://blogit.create.pt/andresantos/2014/11/07/pre-set-common-viewmodel-preperties-before-action-result/#respond</comments>
		
		<dc:creator><![CDATA[André Santos]]></dc:creator>
		<pubDate>Fri, 07 Nov 2014 15:41:17 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[action filter]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[filter provider]]></category>
		<category><![CDATA[global filters]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[mvc 5]]></category>
		<category><![CDATA[viewmodel]]></category>
		<guid isPermaLink="false">http://blogit.create.pt/andresantos/?p=121</guid>

					<description><![CDATA[<p>So, I defined a master model that is shared by every view in my MVC site. This model defines a bunch of properties that are always used on every page, such as a page title, page description, the google tag manager code, etc. I need this model to be filled before the action result, so that [&#8230;]</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2014/11/07/pre-set-common-viewmodel-preperties-before-action-result/">Pre-set common viewmodel properties before action result</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>So, I defined a master model that is shared by every view in my MVC site. This model defines a bunch of properties that are always used on every page, such as a page title, page description, the google tag manager code, etc.</p>
<p>I need this model to be filled before the action result, so that I can use those properties on the view.</p>
<p>In order to do this, I created a custom Action Filter Attribute that is used by every action:</p>
<pre class="brush: csharp; title: SetupMasterModelActionFilter.cs; notranslate">

    public class SetupMasterModelActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            ViewResultBase result = filterContext.Result as ViewResultBase;
            if (result == null)
            {
                return;
            }

            MasterModel model = result.Model as MasterModel;
            if (model == null)
            {
                return;
            }

            SetupMasterModel(model);
            SetupViewBag(result, model);
        }

        private void SetupMasterModel(MasterModel model)
        {
            ...
        }

        private void SetupViewBag(ViewResultBase result, MasterModel model)
        {
            ...
        }
   }
</pre>
<p><span id="more-6463"></span></p>
<p>In order to execute this filter before every action I had to register it in the GlobalFilters at the Global.asax.cs file:</p>
<pre class="brush: csharp; title: Global.asax.cs; notranslate">

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            GlobalFilters.Filters.Add(new SetupMasterModelActionFilter());

            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
</pre>
<p>There are, however, some pages that don&#8217;t use this master model, so I need to exclude the use of this filter on certain actions. In order to do this, I created a new Filter Provider that looks for an exclude filter and filters out the one targeted:</p>
<pre class="brush: csharp; title: ExcludeFilterProvider.cs; notranslate">

    public class ExcludeFilterProvider : IFilterProvider
    {
        private FilterProviderCollection filterProviders;

        public ExcludeFilterProvider(IFilterProvider&#x5B;] filters)
        {
            this.filterProviders = new FilterProviderCollection(filters);
        }

        public IEnumerable&lt;Filter&gt; GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            Filter&#x5B;] filters = this.filterProviders.GetFilters(controllerContext, actionDescriptor).ToArray();

            IEnumerable&lt;ExcludeFilterAttribute&gt; excludeFilters = (from f in filters where f.Instance is ExcludeFilterAttribute select f.Instance as ExcludeFilterAttribute);

            List&lt;Type&gt; filterTypesToRemove = new List&lt;Type&gt;();
            foreach (ExcludeFilterAttribute excludeFilter in excludeFilters)
            {
                filterTypesToRemove.Add(excludeFilter.FilterType);
            }

            IEnumerable&lt;Filter&gt; res = (from filter in filters where !filterTypesToRemove.Contains(filter.Instance.GetType()) select filter);
            return res;
        }
    }
</pre>
<p>The exclude filter attribute that will decorate the excluded actions:</p>
<pre class="brush: csharp; title: ExcludeFilterAttribute.cs; notranslate">

    public class ExcludeFilterAttribute : FilterAttribute
    {
        private Type filterType;

        public ExcludeFilterAttribute(Type filterType)
        {
            this.filterType = filterType;
        }

        public Type FilterType
        {
            get
            {
                return this.filterType;
            }
        }
    } 

</pre>
<p>And we add the new provider at the start of the application and remove the old ones:</p>
<pre class="brush: csharp; title: Global.asax.cs; notranslate">

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            GlobalFilters.Filters.Add(new SetupMasterModelActionFilter());

            IFilterProvider&#x5B;] providers = FilterProviders.Providers.ToArray();
            FilterProviders.Providers.Clear();
            FilterProviders.Providers.Add(new ExcludeFilterProvider(providers));

            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }

</pre>
<p>With this, every action will setup the master model properties except the ones that implement the exclude filter:</p>
<pre class="brush: csharp; title: HomeController.cs; notranslate">

    public class HomeController : Controller
    {
        &#x5B;ExcludeFilter(typeof(SetupMasterModelActionFilter))]
        public ActionResult Index()
        {
            HomeModel model = new HomeModel();

            return View(model);
        }
    }

</pre>
<p>The post <a href="https://blogit.create.pt/andresantos/2014/11/07/pre-set-common-viewmodel-preperties-before-action-result/">Pre-set common viewmodel properties before action result</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blogit.create.pt/andresantos/2014/11/07/pre-set-common-viewmodel-preperties-before-action-result/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
