MVC vs Web Forms Friday, July 31, 2015 12:32 PM ASP.NET Web Forms: UI as a hierarchy of server-side control objects. Each control kept track of its own state across requests. Each control used the View State facility, and connected client-side events (button clicks) with server-side event handler code. - Slow response times due to ViewState being transferred in every request - Limited control over HTML - Low testability Changes: HTML5, REST web services. ASP.NET MVC 5 is built for.net 4.5.1. ASP.NET MVC: 1. Implements a modern variant of the MVC pattern that is especially suitable for Web applications. 2. You can easily replace components, such as the routing system, the view engine, and the controller factory, with a different one of your own implementation 3. Control over the requests passing between the browser and server New features in ASP.NET MVC 5: Authentication filters: A new kind of filter that can be used to include different types of authentication within the same controller Filter overrides: A new kind of filter that is applied to action methods to prevent filters defined globally or on the controller from taking effect Attribute routing: A set of attributes that allow URL routes to be defined within the controller class New features in ASP.NET 4.5.1: - Identity API: replaces the Membership system (not covered in book) ASP.NET MVC 5 Page 1
MVC Introduction Friday, July 31, 2015 Controllers, actions, routes Incoming requests are handled by controllers, which are C# classes (usually inheriting from System.Web.Mvc.Controller). Each public method in a controller is known as an action method, meaning you can invoke it from the Web via some URL to perform an action. MVC applications use the ASP.NET routing system, which decides how URLs map to controllers and actions. To render a view: create the ViewResult by calling the View() method with no parameters. This tells MVC to render the default view for the action. The convention is that the view has the name of the action method and is contained in a folder named after the controller. The.cshtml file extension denotes a C# view that will be processed by Razor. Early versions of MVC relied on the ASPX view engine, for which view files have the.aspx extension. One way to pass data from the controller to the view is by using the dynamic ViewBag object, which is a member of the Controller base class. HTML helpers 2:21 PM They generate the HTML for elements, setting the "type" parameters for input elements, setting the "id" and "name" attributes, etc. The ActionLink method takes two parameters: the first is the text to display in the link, and the second is the action to perform when the user clicks the link. BeginForm: generates an HTML form element configured to post back to the action method. If no arguments are passed, it posts back to the same URL that the HTML document was requested from TextBoxFor DropDownListFor HTML Helpers with Lambda Expressions (preferred because of Intellisense) @Html.TextBoxFor(x => x.phone) HTML Helpers without Lambda Expressions @Html.TextBox("Phone") A strongly typed view is intended to render a specific domain type and it includes the following statement: @model Program.Models.GuestResponse To access the model properties, just use the following syntax: @Model.Property Handling forms & server-side validation 2 methods in controller: 1 annotated with [HttpGet] that shows the form. 1 annotated with [HttpPost] that is called when the user submits the form. Declarative validation rules in the domain model with data annotations. These translate into HTML data-* attributes. - Required: will report an error if the value is null - RegularExpression ASP.NET MVC 5 Page 2
The controller validates the model through a call to if (ModelState.IsValid) If one property fails validation, the class "input-validation-error" is added to the HTML input tag. The client shows the validation summary through @Html.ValidationSummary() ASP.NET MVC 5 Page 3
Razor Friday, July 31, 2015 5:54 PM Razor Layouts Razor views are compiled into C# classes in an MVC application. The View() constructor can receive either a view name or an object model. The base class that is used defines the Layout property. Layouts are templates that contain markup that you use to create consistency across your app. Files in the Views folder whose names begin with an underscore (_) are not returned to the user, which allows the file name to differentiate between views that you want to render and the files that support them. Layouts, which are support files, are prefixed with an underscore. The _ViewStart.cshtml is a special file that MVC will look for, and if it exists it will override the Layout property. Razor Syntax Each of the content lines in the views either is a Razor directive or starts with an HTML element. Razor statements start with the @ character. Declare the view model object type using @model (lower case m) and access the Name property using @Model (upper case M). You should not use Razor to perform business logic or manipulate your domain model objects in any way. Equally, you should not format the data that your action method passed to the view. Instead, let the view figure out data it needs to display. Conditional statements: The @: characters prevent Razor from interpreting this as a C# statement, which is the default behavior when it encounters text. The @using statement brings a namespace into context for a view. There are, confusingly, two Web.config files in a Razor MVC project: the main one, which resides in the root directory of the application project, and the view-specific one, which is in the Views folder. Every namespace that I refer to in a Razor view needs to be used explicitly, declared in the web.config file or applied with a @using expression. Partial view: a fragment of content that you can embed into another view. A partial view is similar to a regular view, except that it produces a fragment of HTML, rather than a full HTML document. @foreach (Product product in Model.Products) @Html.Partial("ProductSummary", product) ASP.NET MVC 5 Page 4
public class NavController : Controller // GET: Menu public PartialViewResult Menu() var categories = this.repository.products.select(p => p.category).distinct().orderby(c => c); return PartialView(categories); Mobile The MVC Framework supports a feature called display modes, which allows you to create different views that are delivered based on the client that has made the request, a feature provided by the ASP.NET Framework. The MVC Framework will automatically identify mobile clients and use the _Layout.Mobile.cshtml file when it is rendering views, seamlessly replacing the _Layout.cshtml file which is used for other clients. ASP.NET MVC 5 Page 5
ASP.NET MVC 5 Page 6 HTML helpers Friday, August 7, 2015 2:12 PM Helpers The ASP.NET MVC Framework has the concept of child actions, which are perfect for creating items such as a reusable navigation control. A child action relies on the HTML helper method called Html.Action, which lets you include the output from an arbitrary action method in the current view. Html.Partial 1. Use Html.Partial when you are rendering static content or, 2. If you are going to pass data from the ViewModel that is being sent to the main view Html.Action 1. Use Html.Action when you actually need to retrieve additional data from the server to populate the partial view Does your menu require a view model, or is it static? If it's a static menu, Html.Partial will fit your needs. Place the static menu content inside the partial view and call Html.Partial where you want it to render. If the menu is being generated off a view model, you can use either Html.Partial or Html.Action Action and Routes don't have to have a 1:1 relationship. ActionLink will generate the URL to get to an action using the first matching route by action name. @Html.ActionLink("Abundant Code on C# and Java Samples", "ActionName", "ControllerName") RouteLink will generate a URL to a specific route determined either by name or route values. @Html.RouteLink("Abundant Code on C# and Java Samples", new action = "ActionName" ) Html.Partial returns a String, Html.RenderPartial calls Write internally, and returns void. // Razor syntax @Html.Partial("ViewName") @ Html.RenderPartial("ViewName"); Ability to access routing information directly from the view. The ViewContext property provides information about the current state of the request that is being processed, including details of the routing information.
Tools: DI, Unit Tests, Mocks Monday, August 3, 2015 12:26 PM DI containers Unit Test Frameworks Mocking tools Ninject Built-in framework Moq Autofac NUnit Rhino Mocks Ninject Steps to embed Ninject at the heart of the MVC application using a constructor injection and with dependency chains: 1. Create a dependency resolver. The IDependencyResolver interface is part of the System.Mvc namespace and the MVC Framework uses it to get the objects it needs. public class NinjectDependencyResolver : IDependencyResolver // create kernel: object that is responsible for resolving dependencies and creating new objects private IKernel kernel; public NinjectDependencyResolver(IKernel kernelparam) kernel = kernelparam; AddBindings(); private void AddBindings() kernel.bind<ivaluecalculator>().to<linqvaluecalculator>(); kernel.bind<idiscounthelper>().to<defaultdiscounthelper>().withpropertyvalue( "DiscountSize", 0M); public object GetService(Type servicetype) return kernel.tryget(servicetype); public IEnumerable<object> GetServices(Type servicetype) return kernel.getall(servicetype); 1. Create a bridge between the NinjectDependencyResolver class and the MVC support for dependency injection in the App_Start/NinjectWebCommon.cs file private static void RegisterServices(IKernel kernel) System.Web.Mvc.DependencyResolver.SetResolver(new Infrastructure.NinjectDependencyResolver(kernel)); 3. Remove the existing dependencies in the Controller by not instantiating any concrete classes. public class HomeController : Controller private IValueCalculator calc; public HomeController(IValueCalculator calcparam) calc = calcparam; // public ActionResult Index() ShoppingCart cart = new ShoppingCart(calc) Products = products ; decimal totalvalue = cart.calculateproducttotal(); return View(totalValue); It is also possible to apply "conditional binding" to choose which implementation will be used for each intereface: Method (kernel.bind<interface>().to<implementation>() Effect ASP.NET MVC 5 Page 7
Method (kernel.bind<interface>().to<implementation>() When(predicate) WhenClassHas<T>() Effect Binding is used when the predicate a lambda expression evaluates to true. Binding is used when the class being injected is annotated with the attribute whose type is specified by T. WhenInjectedInto<T>() Binding is used when the class being injected into is of type T. Finally, it's also possible to specify the "scope" of each dependency created. InScope InSingletonScope: creates a single instance which is shared throughout the application. InTransientScope: creates a new object for each dependency that is resolved. InThreadScope: creates a single instance which is used to resolve dependencies for objects requested by a single thread. InRequestScope: one class for each HTTP request. Mocks The paid-for versions of Visual Studio include support for creating mock objects through a feature called fakes. Example with Moq: [TestMethod] public void Sum_Products_Correctly() // arrange Mock<IDiscountHelper> mock = new Mock<IDiscountHelper>(); mock.setup(m => m.applydiscount(it.isany<decimal>())).returns<decimal>(total => total); var target = new LinqValueCalculator(mock.Object); // act var result = target.valueproducts(products); // assert Assert.AreEqual(products.Sum(e => e.price), result); The It.Is method is the most flexible way of setting up specific behaviors for different parameter values because you can use any predicate that returns true or false. The Methods of the It Class: Method Description Is<T>(predicate) Specifies values of type T for which the predicate will return true IsAny<T>() Specifies any value of the type T. IsInRange<T>(min, max, kind) Matches if the parameter is between the defined values and of type T. IsRegex(expression) Matches a string parameter if it matches the specified regular expression ASP.NET MVC 5 Page 8
ASP.NET MVC 5 Page 9 Entity Framework Monday, August 3, 2015 5:54 PM Use LocalDb for development purposes. The DbContext class specifies a database schema and each property specifies a table. public class EFDbContext : DbContext // define a property for each table in the database public DbSet<Product> Products get; set;
MVC projects Thursday, August 6, 2015 3:03 PM Folder structure App_Data: where you put private data, such as XML files or databases if you are using SQL Server Express, SQLite, or other file-based repositories. IIS will not serve the contents of this folder. App_Start: contains some core configuration settings for your project, including the definition of routes and filters and content bundles Areas: way of partitioning a large app into smaller pieces. Content: static content such as CSS files and images. Controllers Models Scripts Views Views/Shared: holds layouts and views that aren't specific to a single controller. Views/Web.config: prevents IIS from serving the content of the "Views" folders. Views must be rendered through an action method. Global.asax: the place to register routing configuration, as well as setup code to run on app initialization or shutdown, or when unhandled exceptions occur. Web.config Conventions Controller classes must have names that end with Controller, but when referencing them, you specify only the first part of the name (this can be changed by creating an implementation of IControllerFactory) Views and partial views go into the folder /Views/Controllername. The default view for an action method should be named after that method. When looking for a view, the MVC Framework looks in the folder named after the controller and then in the /Views/Shared folder Debugging When <compilation debug="true"/> is switched on within the application s web.config file, it causes a number of non-optimal things to happen including: 1. You will see a lot more files in Temporary ASP.NET files folder. 2. Your pages will not timeout. 3. Batch compilation will be disabled. 4. The System.Diagnostics.DebuggableAttribute gets added to all generated code which causes performance degradation. 5. All client-javascript libraries and static images that are deployed via WebResources.axd will not be cached locally within the browser. ASP.NET MVC 5 Page 10
Routing a request Tuesday, August 4, 2015 1:05 PM The ASP.NET routing system is used by MVC to handle incoming requests from clients, but it also generates outgoing URLs that conform to the URL scheme and that can be embedded in Web pages. Incoming URLs The routing system checks to see if a URL matches a disk file before evaluating the application s routes. This behavior can be reversed so that the routes are evaluated before disk files are checked by setting the RouteExistingFiles property of the RouteCollection to true. There are two ways to create routes in an MVC Framework application: convention-based routing and attribute routing. Attribute routing is new to MVC 5. Each route contains a URL pattern, which is compared to incoming URLs. If a URL matches the pattern, then it is used by the routing system to process that URL. GetRouteData(HttpContextBase httpcontext): This is the mechanism by which inbound URL matching works. The framework calls this method on each RouteTable.Routes entry in turn, until one of them returns a non-null value. Routes can be customized by changing the way that they match URL segments Routes can also be customized by using default values and optional segments. Routes can be constrained to narrow the range of requests that they will match built-in constraints custom constraint classes. Some rules: By default, a URL pattern will match any URL that has the correct number of segments. URL patterns are conservative, and will match only URLs that have the same number of segments as the pattern. URL patterns are liberal. If a URL does have the correct number of segments, the pattern will extract the value for the segment variable, whatever it might be. The routing system does not know anything about an MVC application, and so URL patterns will match even when there is no controller or action that corresponds to the values extracted from a URL Convention-based routing public static void RegisterRoutes(RouteCollection routes) Route myroute = new Route("controller/action", new MvcRouteHandler()); routes.add("myroute", myroute); // equivalent to routes.maproute("myroute", "controller/action"); The MapRoute method is solely for use with MVC applications. ASP.NET Web Forms applications can use the MapPageRoute method, also defined in the RouteCollection class. Default values can be specified for segments. ASP.NET MVC 5 Page 11
Default values can be specified for segments. public static void RegisterRoutes(RouteCollection routes) routes.maproute("myroute", "controller/action", new controller = "Home", action = "Index" ); We should represent the root URL as ~/, as this is how ASP.NET presents the URL to the routing system. The order in which the routes are added to the RouteCollection is important. The most specific rules must be placed first, because the routing system stops at the first match. It is possible to support the renaming of controllers and actions and not lose the bookmarks created. Example: public static void RegisterRoutes(RouteCollection routes) routes.maproute("shopschema2", "OldController/OldAction", new controller = "NewController", action = "NewAction" ); Segment variables with special meaning: - controller - action - area We can access any of the segment variables in an action method by using the RouteData.Values property, or (more elegantly), by adding new parameters to the action method that match these segment variables. Optional parameters: they will be "null" unless specified. To accept a variable number of URL segments: designate one of the segment variables as a catchall, done by prefixing it with an asterisk (*). We can tell the MVC Framework to give preference to certain namespaces when attempting to resolve the name of a controller class. However, the namespaces added to a route are given equal priority. The MVC Framework does not check the first namespace before moving on to the second and so forth. ASP.NET MVC 5 Page 12
We can tell MVC to just look in one namespace and throw errors if not found. myroute.datatokens["usenamespacefallback"] = false; Constraints for values: Attribute-based routing Attribute routing is disabled by default and can be enabled by routes.mapmvcattributeroutes(). The Route attribute stops convention-based routes from targeting an action method even if attribute routing is disabled. The RoutePrefix attribute can be used on a class and Route can be used on actions. Note that if Route(~/Home) is used, the RoutePrefix will be ignored for that particular action. Route constraints: Outgoing URLs & Areas ASP.NET MVC 5 Page 13
Areas use the NuGet package <package id="microsoft.aspnet.web.optimization" /> ActionLink will generate an <a> tag that points to a specific route. This can be in the same controller or in a different controller; there are many overloads. Url.Action will just generate a URL with no <a> tag. <!-- Same controller --> @Html.ActionLink("This is an outgoing URL to the About page", "About") <!-- Different controller and with a segment variable ("page") --> @Html.ActionLink("Click me", "List", "Catalog", new page = 789, null) <!-- This wi ll just output an URL --> This is a URL: @Url.Action("Index", "Home", new id = "MyId" ) Generating outgoing URLs in a controller: GetVirtualPath(RequestContext requestcontext, RouteValueDictionary values): This is the mechanism by which outbound URL generation works. The framework calls this method on each RouteTable.Routes entry in turn, until one of them returns a non-null value. Areas - They organize a complex app into manageable parts. - They should be registered before routes in Global.asax. - They CAN cause namespace collisions. For example, if there is a very generic route to the Home Controller and it doesn't specify a priority of namespaces - The RouteArea attribute moves all of the routes defined by the Route attribute into the specified area - The RouteArea has no effect on action methods to which the Route attribute has not been defined. - To create a link to an action in a different area, or no area at all, you must create a variable called area and use it to specify the name of the area you want, like this: @Html.ActionLink("Click me to go to another area", "Index", new area = "Support" ) ASP.NET MVC 5 Page 14
MvcRouteTester https://github.com/anthonysteele/mvcroutetester/wiki/usage ASP.NET MVC 5 Page 15
Handling a request Friday, August 7, 2015 6:24 PM Controllers can be created in two ways: implementing the IController interface from the System.Web.Mvc namespace and implement public void Execute(RequestContext requestcontext), or they can inherit from System.Web.Mvc.Controller. The properties defined by the RequestContext class are: HttpContext: Returns an HttpContextBase object that describes the current request RouteData: Returns a RouteData object that describes the route that matched the request Accessing requests' data There are 3 ways to access the request's data: 1. Extract it from a set of context objects: HttpContext will give information about an individual HTTP request. ControllerContext will give information about an HTTP request for a specified controller. 2. Have the data passed as parameters to your action method. The names of the parameters are treated case-insensitively, so that an action method parameter called city can be populated by a value from Request.Form["City"], for example. If the MVC Framework cannot find a value for a reference type parameter (such as a string or object), the action method will still be called, but using a null value for that parameter. If a value cannot be found for a value type parameter (such as int or double), then an exception will be thrown, and the action method will not be called. Using the context Using parameters 3. Explicitly invoke the framework s model binding feature. Writing a response 1. Response.Write and Response.Redirect, etc. Writes the HTML directly to the output. Not recommended, but there is no other choice if we implement IController. 2. Using ActionResults. The MVC Framework uses action results to separate stating intentions from executing intentions. When the MVC Framework receives an ActionResult object from an action method, it calls the ExecuteResult method defined by that object. a. RedirectResult: can be temporary (302) or permanent (301). b. RedirectToRoute: issues an HTTP 301 or 302 redirection to an action method or specific route entry, generating a URL according to your routing configuration c. d. e. f. g. h. i. ViewResult PartialViewResult ContentResult: returns raw textual data to the browser, optionally setting a content-type header FileResult JsonResult HttpUnauthorizedResult, HttpNotFoundResult, HttpStatusCodeResult EmptyResult ASP.NET MVC 5 Page 16
Filters Monday, August 10, 2015 3:31 PM Filters are.net attributes that add extra steps to the request processing pipeline. The goal of filtering is to put code that is required across the application in one reusable location. MVC 5 supports 6 different types of filters: Filter Type Interface Description Authentication Authorization IAuthenticationFil ter IAuthorizationFilt er Runs first Action IActionFilter Runs before and after the action method Runs second. Enforces authorization policy, ensuring that action methods can be invoked only by approved users Result IResultFilter Runs before and after the action result is executed Exception IExceptionFilter Runs only if another filter, the action method, or the action result throws an exception (new in MVC 5) Overrides Authorization Filters IOverrideFilter 2 ways of implementing them: - Inherit from AuthorizeAttribute and override AuthorizeCore(HttpContextBase) HttpContextBase provides access to information about the request, but not about the controller or action method Properties of AuthorizeAttribute: Users Roles - Implement IAuthorizationFilter and override OnAuthorization(AuthorizationContext) - not recommended AuthorizationContext provides a much wider range of information, including routing details and the current controller and action method Authentication Filters 1 way of implementing them: - Implement IAuthenticationFilter and override: OnAuthentication(AuthenticationContext): should be used for setting the principal, the principal being the object identifying the user. We can also set a result in this method like an HttpUnauthorisedResult. OnAuthenticationChallenge(AuthenticationChallengeContext): used to add a "challenge" to the result before it is returned to the user. The idea is that this method can be used to contribute to the result, rather than perform critical authorization checks. Exception Filters The exception can come from the following locations: Another kind of filter (authorization, action, or result filter) The action method itself When the action result is executed 2 ways: 1. Implement the IExceptionFilter and override OnException(ExceptionContext), and derive from FilterAttribute. -- not recommended ExceptionContext properties: ActionDescriptor: details of the action method Result: the result for the action method Exception ExceptionHandled: "true" if another filter handled the exception Example: ASP.NET MVC 5 Page 17
2. Use the built-in HandleErrorAttribute. The HandleErrorAttribute filter works only when custom errors are enabled in the Web.config file. When rendering a view, the HandleErrorAttribute filter passes a HandleErrorInfo view model object. This class has the following properties: a. ExceptionType: The exception type handled by this filter b. View: The name of the view template that this filter renders. c. Master: The name of the layout used when rendering this filter s view To keep in mind: When using an exception filter that relies on a view to display the exception, be careful to test that view thoroughly because that view can generate other exceptions as well! Action Filters They operate before or after an action has completed (but before the result is processed). Sample application: to measure howlong an action takes to execute. Some of the most common action filters: - OutputCache: this attribute can be applied either on an individual action method or on the entire controller to improve performance by caching the responses sent to the users. It has the following properties: Duration specified in seconds, it tells us how long the response will be cached. VaryByParam vary caching using parameters like Query String. Location where the cache will be stored. Can be "server", "client", "server and client", etc. - ValidateInput: by default all user posted data (i.e. query string params, form element, etc.) are validated for any potential dangerous content (i.e. HTML tag or script) to avoid XSS attacks. But sometimes we need to accept such HTML content from user. In such scenarios we can use the ValidateInput action filter to allow users to post HTML content and to bypass request validation forspecific action method. But we must ensure that we apply our custom logic to avoid any malicious user input. - HandleError: used to redirect to a custom error page when an error is triggered by the action of the controller. Example: [HandleError(ExceptionType = typeof(nullreferenceexception), View = "NullError")] Result Filters They operate before or after a result is processed. ASP.NET MVC 5 Page 18
The built-in ActionFilterAttribute class can be used, and it is both an action and result filter. The ActionFilterAttribute class implements the IActionFilter and IResultFilter interfaces, which means that the MVC Framework will treat derived classes as both types of filters, even if not all of the methods are overridden. Advanced features - The normal way of using filters is to apply attributes, but the Controller class implements the IAuthenticationFilter, IAuthorizationFilter, IActionFilter, IResultFilter, and IExceptionFilter interfaces. This is useful if we are creating a base Controller class. - Global filters are applied to all the action methods in all the controllers. They are added to the App_Start folder and then a call to FilterConfig.RegisterGlobalFilters must be added to Global.asax. - Filter execution can be ordered. The Order parameter (default: -1) takes an int value, and the MVC Framework executes the filters in ascending order. The OnActionExecuting methods are executed in the order specified, but the OnActionExecuted methods are executed in the reverse order. - Filter overrides: If you want an action method to just be affected by the filters that have been directly applied to it. Thistells the MVC Framework to ignore any filters that have been defined at a higher-level, such as the controller or globally Example: Simple Filter Override Filter Controller Result without override filter Result with override filter ASP.NET MVC 5 Page 19
Controller extensibility Tuesday, August 11, 2015 12:16 PM Controller Factories This interface can be implemented to change the way MVC creates controllers and prioritizes namespaces. We can tell the MVC Framework to use the custom controller factory through the ControllerBuilder class. We need to register custom factory controllers when the application is started, which means using the Application_Start method in the Global.asax file. Controller Activators Classes that specify how a Factory instantiates controllers, and they can be injected into the default factory. ASP.NET MVC 5 Page 20
Classes that specify how a Factory instantiates controllers, and they can be injected into the default factory. Action Invokers Class that selects an action method to execute. Different controllers in the same application can use different action invoke rs through the Controller.ActionInvoker property. When using the built-in action invoker (ControllerActionInvoker class), a method must meet the following criteria to be classified as an "action": The method must be public. The method must not be static. If the action value that the routing system produces is Index, then the ControllerActionInvoker will look for a method called Index that fits the action criteria. The mapping "action name <-> method name" can be modified by decorating the method with the attribute [ActionName]. Action Selection 3 ways to specify how to select an action to execute: [HttpGet] [HttpPost] [HttpPut] attributes [NonAction] attributes Create a custom class that derives from ActionMethodSelectorAttribute and decorate the method with it. Example: Process of choosing an action method: 1. Select methods that meet the "public, non-static" criteria 2. Select subset of methods that have the same name as the target action, or match the [ActionName] attribute 3. Discard methods that have any action method selector attributes that return false for the current request 4. If no action methods left, call HandleUnknownAction which by default throws a 404 error. 5. If there is exactly one action method with a selector left, then this is the method that is used. If more than one, throw an "ambiguous request" exception. 6. If there are no action methods with selectors, then the invoker looks at those without selectors. If there is exactly one such method, then this is the one that is invoked. If more than one, throw an "ambiguous request" exception. (Bottom line: methods decorated with action selection attributes have priority over methods that don't have any). We can override how to handle an unknown action: ASP.NET MVC 5 Page 21
Sessionless Controllers These are just like regular controllers, with two exceptions: 1. The MVC Framework will not load or store session state when they are used to process a request, and 2. Overlapping requests can be processed simultaneously. (If the controller allows sessions, ASP.NET will process only one queryfor a given session at a time and queue concurrent requests). There are 4 possible values for the SessionStateBehavior: - Default: determines the session state configuration from HttpContext. - Required: full read-write session state enabled. - ReadOnly: read-only session state enabled. - Disabled The MVC Framework will throw an exception if a controller class is decorated with [SessionState(SessionStateBehavior.Disabled)] and we try to read or set Session["whatever]. Async controllers Asynchronous controllers are useful only for actions that are I/O- or network-bound. Using an asynchronous controller frees up the worker thread so that it can process other queries. Example: ASP.NET MVC 5 Page 22
Session management Tuesday, August 4, 2015 3:08 PM ASP.NET has a session feature that uses cookies or URL rewriting to associate multiple requests from a user together to form a single browsing session. A related feature is session state, which associates data with a session. Example: private Cart GetCart() Cart cart = (Cart)Session["Cart"]; if (cart == null) cart = new Cart(); Session["Cart"] = cart; return cart; TempData: key/value dictionary that is deleted at the end of the HTTP request. You store something inside TempData and then redirect. In the target controller action to which you redirected you could retrieve the value that was stored inside TempData. ASP.NET MVC will automatically expire the value that was stored in TempData once you read it. Vs ViewBag: passes data between controller and view. It's a DYNAMIC object. Valid only for the duration of the current request. Vs SessionData: the message is persistent until it is explicitly removed. Vs ViewData: passes data between controller and view. It's a DICTIONARY object. Valid only for the duration of the current request. Sessionless Controllers These are just like regular controllers, with two exceptions: 1. The MVC Framework will not load or store session state when they are used to process a request, and 2. Overlapping requests can be processed simultaneously. There are 4 possible values for the SessionStateBehavior: - Default: determines the session state configuration from HttpContext. - Required: full read-write session state enabled. - ReadOnly: read-only session state enabled. - Disabled The MVC Framework will throw an exception if a controller class is decorated with [SessionState(SessionStateBehavior.Disabled)] and we try to read or set Session["whatever]. ASP.NET MVC 5 Page 23
Views Tuesday, August 11, 2015 5:02 PM The purpose of the view engine is to produce a ViewEngineResult object that contains either an Iview or a list of the places where it searched for a suitable view. The static ViewEngine.Engines collection contains the set of view engines that are installed in the application. The MVC Framework supports the idea of the re being several engines installed in a single application. When a ViewResult is being processed, the action invoker obtains the set of installed view engines and calls their FindView methods in turn. If I want to ensure that only my custom view engine is used, then I have to call the Clear method before I register my engine in the Global.asax file. The views are translated into C# classes, and then compiled. The initial request to MVC application triggers the compilation process for all views. Razor View C# Class How to add dynamic content to a Razor view: Inline C# code Built-in or custom HTML helper methods to generate elements Sections that will be inserted into layouts at specific locations (if no section is defined for a piece of markup it will be inserted at the RenderBody() call) Partial views: they cannot perform business logic Child actions: UI controls that need to contain business logic ASP.NET MVC 5 Page 24
ASP.NET MVC 5 Page 25 Extra Friday, July 31, 2015 3:37 PM Post-Redirect-Get Pattern When a web form is submitted to a server through an HTTP POST request, a web user that attempts to refresh the server response in certain user agents can cause the contents of the original HTTP POST request to be resubmitted, possibly causing undesired results, such as a duplicate web purchase. To avoid this problem: use the POST/REDIRECT/GET (PRG) pattern instead of returning a web page directly, the POST operation returns a redirection command. The HTTP 1.1 specification introduced the HTTP 303 ("See other") response code to ensure that in this situation, the web user's browser can safely refresh the server response without causing the initial HTTP POST request to be resubmitted UI: Bootstrap Form-group Form-control Btn-block Visible-xs, hidden-xs Dependency Injection pattern Repository pattern 1. 2. Constructor injection and setter injection through INTERFACES IoC containers: handle dependency chain resolution, object lifecycle management (singleton, transient, instance-per-thread, instance-per-http-request, instance-from-a-pool), configuration of constructor parameter values a. Ninject b. Unity
Validation Wednesday, August 5, 2015 4:49 PM @Html.ValidationSummary() @Html.ValidationMessage(property.PropertyName) It can be server-side or client-side. Server-side [HttpPost] public ActionResult Edit(Product product) if (ModelState.IsValid) this.repository.saveproduct(product); TempData["message"] = string.format("0 has been saved!", product.name); return RedirectToAction("Index"); else // something wrong with the data. Return to "edit" view return View(product); Client-side The following statements disable client-side validation for the view to which they are added. @ ViewBag.Title = "Edit Product ID" + @Model.ProductID; Layout = "~/Views/Shared/_AdminLayout.cshtml"; HtmlHelper.ClientValidationEnabled = true; HtmlHelper.UnobtrusiveJavaScriptEnabled = true; You can disable client-side validation for the entire application by setting values in the Web.config file, like this: <appsettings> <add key="webpages:version" value="3.0.0.0" /> <add key="webpages:enabled" value="false" /> <add key="clientvalidationenabled" value="true" /> <add key="unobtrusivejavascriptenabled" value="true" /> <add key="email.writeasfile" value="true" /> </appsettings> ASP.NET MVC 5 Page 26
ASP.NET MVC 5 Page 27 Security Wednesday, August 5, 2015 5:30 PM
ASP.NET MVC 5 Page 28 Bundles Friday, August 14, 2015 3:26 PM The goal is to turn the JavaScript and CSS files into bundles, which allow us to treat several related files as a single unit, therefore making one request and not one per CSS/JS file. The convention is to define bundles in a file called BundleConfig.cs, which is placed in the App_Start folder. Styles are represented by the StyleBundle class and scripts are represented by the ScriptBundle class. Both take a single constructor argument that is the path that the bundle will be referenced by. The path is used as a URL for the browser to request the contents of the bundle.
Helper methods Wednesday, August 12, 2015 1:55 PM Normal helper methods The following HTML helpers generate a specific type of element, which means that I have to decide in advance what kinds of elements should be used to represent model properties and to manually update the views if the type of a property changes. 1. Inline helpers: defined and used directly in the view. Can't reuse them in other views. Definition (like a function, but with no return value) Use 2. External helpers: defined as an extension method of HtmlHelper. Definition Use Note that the raw text sent to the view is NOT encoded, therefore it can be potentially unsafe. To alert the view engine thatthe content is safe, there are 2 ways: a. Change the return type of the helper to string b. User HtmlHelper.Encode(string) 3. Useful members of the TagBuilder class: InnerHtml SetInnerText(string text) AddCssClass(string class) MergeAttribute(string attribute, string value, bool replaceifexisting) Built-in helpers a. Html.BeginForm and Html.EndForm (can be simplified to @using(html.beginform))) Razor Html 2. Html.BeginRouteForm(): to ensure that a particular route is used (e.g. by name) 3. Input element helpers: for the following methods, the 1st argument is used to set the value of the id and name attributes for the input element, and the 2nd argument is used to set the value attribute of the field. Razor @Html.Hidden("myHidden", "val") @Html.RadioButton("female", "val", true) @Html.Password("myPassword", "val") @Html.TextArea("comments", "val", 5, 20, null) @Html.TextBox("myTextbox", "val") Html <input type="hidden" id="myhidden" name="myhidden" value="val" /> <input type="radio" id="female" name="female" value="val" /> <input type="password" id="mypassword" name="mypassword" value="val" /> <textarea id="comments" name="comments" rows="5" cols="20">val</textarea> <input type="text" id="mytextbox" name="mytextbox" value="val" /> @Html.CheckBox("giftwrapped", false) <input id="giftwrapped" name="giftwrapped" type="checkbox" value="true" /> <input name="giftwrapped" type="hidden" value="false" /> 4. If the second argument (for the value) is omitted, the MVC framework will try to find some item of data that corresponds to the key. E.g for @Html.TextBox("DataValue"), the following locations are checked: ViewBag.DataValue @Model.DataValue There are also strongly-typed versions which take in a lambda expression. Examples: @Html.TextBoxFor(m => m.firstname) @Html.CheckBoxFor(m => m.isapproved) Select element helpers: They take SelectList or MultiSelectList parameters ASP.NET MVC 5 Page 29
4. Select element helpers: They take SelectList or MultiSelectList parameters @Html.DropDownList("myList", new SelectList(Enum.GetNames(typeof(AspNet_HtmlHelpers.Models.Role)))) @Html.DropDownListFor(x => x.gender, new SelectList(Enum.GetNames(typeof(AspNet_HtmlHelpers.Models.Gender)))) @Html.ListBox("myList", new MultiSelectList(new[] "A", "B" )) @Html.ListBoxFor(x => x.phonenumbers, new MultiSelectList(new int[] 0, 1,2)) Templated Helper Methods These are more advanced. We specify the property we want to display and let the MVC Framework figure out what HTML elements are required. This usually means decorating each attribute of the model with special attributes to give more information. Helpers: @Html.Editor("property") @Html.EditorFor(x => x.property) @Html.Display("property") @Html.DisplayFor(x => x.property) @Html.Label("property"); @Html.LabelFor(x => x.property) Attributes: [HiddenInput]: will render a read-only view of the property. If I want to hide a property entirely, then I can set the value of the DisplayValue property to false. [ScaffoldColumn(false)]: completely exclude a property from the generated HTML. The ScaffoldColumn attribute doesn t have an effect on the per-property helpers, such as EditorFor. If I call @Html.EditorFor(m => m.personid) in a view, then an editor for the PersonId property will be generated, even when the ScaffoldColumn attribute is present. [DisplayName]: changes the value of the label associated to the model [DataType]: can be PhoneNumber, EmailAddress, Url, Text, MultilineText [UIHint]: specify the template used to render HTML for a property. We can create our own templates! The attributes need not be in the model class. They can be in a metadata class, and mark each class with the partial keyword. Then, annotate the model class with [MetadataType(typeof(ModelMetaData))]. Scaffolding helpers are not recursive. Given an object to process, a scaffolding templated helper method will generate HTML only for simple property types and will ignore any properties that are complex objects. If I want to render HTML for a complex property, I have to do it explicitly by making a separate call to a templated helper method. Url Helpers ASP.NET MVC 5 Page 30
URL and Ajax Helpers Thursday, August 13, 2015 12:34 PM URL Helpers Helper @Url.Content("~/Content/Site.css") @Url.Action("GetPeople", "People") @Url.RouteUrl(new controller = "People", action="getpeople") @Html.ActionLink("My Link", "Index", "Home") @Html.RouteLink("My Link", new controller = "People", action="getpeople") @Html.RouteLink("My Link", "FormRoute", new controller = "People", action="getpeople") Result /Content/Site.css /People/GetPeople /People/GetPeople <a href="/">my Link</a> <a href="/people/getpeople">my Link</a> <a href="/app/forms/people/getpeople">my Link</a> Ajax Helpers The unobtrusive Ajax feature is set up in two places in the application. 1. In the Web.config file the configuration/appsettings element contains an entry for the UnobtrusiveJavaScriptEnabled property, which must be set to true. 2. Add references to the jquery JavaScript libraries that implement the unobtrusive Ajax functionality in the view (or layout file). There are two flavors of Ajax helpers: 1. Ajax unobtrusive forms 2. Ajax links The Ajax requests can be configured via an AjaxOptions object which translates to data-* attributes. To support fallback in case the browser doesn't have JavaScript enabled, set the "Url" property of the object, which will override the action of the form. ASP.NET MVC 5 Page 31
In an action method, it is possible to detect whether the incoming request is from an Ajax call by calling Request.IsAjaxRequest(). This relies on the fact that the header "X- Requested-With" has "XmlHttpRequest". In many cases it is a better idea to separate the actions depending on the type of data they retrieve. ASP.NET MVC 5 Page 32
Model binding Tuesday, August 4, 2015 3:43 PM The MVC Framework uses a system called model binding to create C# objects from HTTP requests in order to pass them as parameter values to action methods. This is how the MVC framework processes forms, for example: it looks at the parameters of the action method that has been targeted and uses a model binder to get the form values sent by the browser and convert them to the type of the parameter with the same name before passing them to the action method. To create a custom model binder, implement the System.Web.Mvc.IModelBinder interface. protected void Application_Start() AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ModelBinders.Binders.Add(typeof(Cart), new CartModelBinder()); public class CartModelBinder : IModelBinder private const string sessionkey = "Cart"; public object BindModel(ControllerContext controllercontext, ModelBindingContext bindingcontext) // Get the Cart from the session Cart cart = null; if (controllercontext.httpcontext.session!= null) cart = (Cart)controllerContext.HttpContext.Session[sessionKey]; // Create the Cart if there wasn't one in the session data if (cart == null) cart = new Cart(); if (controllercontext.httpcontext.session!= null) // Set the cart in the sessions controllercontext.httpcontext.session[sessionkey] = cart; // Return the cart return cart; Benefits of model binding: 1. Separate the logic to create a Model object from that of the controller. 2. Any controller that works with Model objects can just declare them as action method parameters and take advantage of the custom model binder. 3. Adds testability to controllers. The default model binder searches 4 locations for data matching the name of the parameter being bound, and stops at the first match: 1. Request.Form 2. RouteData.Values 3. Request.QueryString 4. Request.Files For complex objects (where a model object Parent has a nested model object Child as property), the model binder will look for a value for Parent.Child. But we can override this behavior with the [Bind(Prefix="")] attribute: ASP.NET MVC 5 Page 33
The [Bind(Exclude="Property")] tells the model binder not to search for data matching "Property". This is useful for sensitive information. We can also apply [Bind(Include)] attributes to only include certain properties. Binding to collections: if an action method receives a parameter IList<AddressSummary>, in the view we can bind to it like this: Custom Value Providers They must implement the interface IValueProvider, be added to the appropriate value provider factory class, and this factory must be registered in Application_Start(). Custom Model Binders ASP.NET MVC 5 Page 34
ASP.NET MVC 5 Page 35
Model validation Friday, August 14, 2015 12:07 PM There are both model errors and model property errors. Model-level validation attributes will not be used when a property- level problem is detected. Most MVC applications use client-side validation for property-level issues and rely on server-side validation for the overall model. Server-side validation Ways to do model validation: 1. With the ModelState class in the controller 2. Overriding the default model binder validation methods (not recommended) OnModelUpdated(): Called when the binder has tried to assign values to all of the properties in the model object SetProperty(): Called when the binder wants to apply a value to a specific property 3. With metadata in the model properties. Either use built-in attributes, inherit from them to add checks, or create new ones by inheriting from ValidationAttribute. [Required] [Range] [Compare("OtherProperty")]: applied to one property that must have the same value as another property (e.g. email address or password) [RegularExpression("pattern")]: it must match the pattern [StringLength(value)]: maximum length "value" [DataType]: can be PhoneNumber, EmailAddress, Url, Text, MultilineText 4. With metadata in the model class. Create custom ones by inheriting from ValidationAttribute. 5. Define a self-validatable model by implementing the interface IValidatableObject and the method IEnumerable<ValidationResult> Validate(validationContext) inside the model. Useful properties and methods to do server-side validation: ModelState.IsValidField: check to see whether the model binder was able to assign a value to a property ModelState.IsValid: If there are no errors, then the helper doesn t generate any HTML ModelState.AddModelError(nameOfProperty, errormessage): register a model-level error by passing the empty string as the first parameter Useful methods to show in the view: @Html.ValidationSummary() @Html.ValidationMessageFor() Individual validation rules are specified using an attribute in the form data-val-<name>, where name is the rule to be applied. Problems with fields are indicated through CSS classes that are automatically inserted. Client-side validation Nuget package Microsoft.jQuery.Unobtrusive.Validation. <appsettings> <add key="webpages:version" value="3.0.0.0" /> <add key="webpages:enabled" value="false" /> <add key="clientvalidationenabled" value="true" /> <add key="unobtrusivejavascriptenabled" value="true" /> </appsettings> Remote validation It is performed on the background. An Ajax request is made to the server to validate a certain model property (not the entire model). The property to validate must be decorated with the [Remote("action", "controller")] attribute. Actions methods that support remote validation must return the JsonResult type. The best approach to remote validation is to accept a string parameter in the action method and perform any type conversion, parsing, or model binding explicitly. ASP.NET MVC 5 Page 36
Web API and SPAs Friday, August 14, 2015 4:55 PM SPA: Web API + MVC Knockout: JavaScript library to implement SPAs. An API Controller has 3 distinctive characteristics: 1. They inherit from ApiController (System.Web.Http namespace) 2. Action methods return a model, rather than ActionResult objects. They do not support returning views or layouts. 3. When a request comes in to the application that matches a Web API route, the action is determined from the HTTP method used to make the request. This can come either from the name of the action method itself or from its attributes ([HttpGet], [HttpPut], etc.) Some other characteristics: - Web API supports JSON and XML, but it gives preference to JSON. - API controllers have their own routing configuration specified in the file App_Start/WebApiConfig.cs. There is no action segment for the routes. Implementing views with Knockout Knockout uses data binding techniques. data-bind attributes are how Knockout lets you declaratively associate viewmodel properties with DOM elements. The differences between using Knockout and Razor expressions are: 1. The data model is no longer included in the HTML sent to the browser 2. Data is processed by the browser 3. Data bindings are live, so if we add or remove items to the "model" they instantly show in the page The call to "ko.observable()" or "ko.observablearray()" turns on the automatic synchronization between the model and the view. Some of the bindings supported by Knockout are: - Foreach: (modelproperty) - (type): (property) "Text: age" will show the value of the age "Value: age" will allow editing the value of the property - Click: (functiontorun) - If: (booleanproperty) - Ifnot: (booleanproperty) ASP.NET MVC 5 Page 37
ASP.NET Identity Wednesday, August 19, 2015 11:59 AM ASP.NET Identity is the API used to manage user data and perform authentication and authorization. It's the first major ASP.NET component to be delivered as OWIN middleware. OWIN is an open-source abstraction layer that isolates a web application from the environment that hosts it. Project Katana is Microsoft's implementation of OWIN. ASP.NET Identity can use the Entity Framework Code First feature to automatically create its schema. Hot to setup Identity using Entity Framework ASP.NET Identity depends on four classes: The user The user manager (which provides the methods CreateAsync, UpdateAsync, DeleteAsync) The user database context The OWIN startup class To setup Identity in a website: 1. Create an "Identity" SQL database. 2. Add the NuGet packages "ASP.NET Identity Entity Framework" and "ASP.NET Identity Owin" to the web project. 3. Modify the Web.config: 4. 5. Create an implementation of the IUser interface (or, if using EF, derive from Microsoft.AspNet.Identity.EntityFramework.IdentityUser) Create an implementation of the class IdentityDbContext and the Db initializer that performs the seed. 6. Create the OWIN startup class and implement the "Configuration" method. ASP.NET MVC 5 Page 38
7. Create the AppUserManager class that inherits from UserManager, and implement the "Create" method. This class can be configured with a custom PasswordValidator, UserValidator and PasswordHasher. How to perform authentication and authorization Authentication is how you check the identity of your users. Through the [Authorize] and [AllowAnonymous] attributes, controllers can access the authentication feature and accept or deny users. When denied, the OWIN start class can specify a login URL. To prevent cross-site request forgeries, ASP.NET MVC supports writing a unique value to a cookie and to the form. When form is submitted, an error is raised if the cookie value doesn't match the form value. To use this feature, decorate the action method with the ValidateAntiForgeryToken attribute and place a call to @Html.AntiForgeryToken() in the forms posting to the method. Authorization is the process of granting access to controllers and action methods to certain users, generally based on role membership. This can be done through the ASP.NET MVC 5 Page 39
Authorization is the process of granting access to controllers and action methods to certain users, generally based on role membership. This can be done through the [Authorize(Roles = "RoleName")] attribute. In order to implement the concept of "roles" we must create two classes: 1. A class that inherits from IdentityRole 2. A class that inherits from RoleManager ASP.NET MVC 5 Page 40
Architecture Thursday, August 20, 2015 3:13 PM Repository pattern: Scalability Planning for scalability might have multiple levels of impact upon other decisions that you might be making around caching, server-side versus client-side processing and data access. There are two primary ways that you can scale: horizontally or vertically. - Horizontally: through web farms and a load balancer that decides which server should be called. Session state information will be affected. - Vertically: adding resources to a single system. This is an easy but limited way of scaling. Web services ASP.NET Web Services (ASMX) allows to roll out a Simple Object Access Protocol (SOAP) based web service. Although ASMX has been superseded by WCF and Web API, many sites still use ASMX to provide their primary web services. The ASMX services should have a WSDL (Web Service Description Language) that describes the services provided. Hybrid applications A hybrid application is an application that is partially deployed on-premise and partly off-premise. - - Client-centric pattern: the client application determines where it needs to make its service calls. System-centric pattern: a service bus (e.g. AppFabric) will distribute service requests to a service in the cloud, on-premise or another source. Session management A session is stored on the server and is unique for a user s set of transactions. The browser needs to pass back a unique identifier, called SessionId, which can be ASP.NET MVC 5 Page 41
A session is stored on the server and is unique for a user s set of transactions. The browser needs to pass back a unique identifier, called SessionId, which can be sent as part of a small cookie or added onto the query string where it can be accessed by the default handler. The surest way to manage state in a distributed application is to implement a sessionless design in which you use a query string or hidden input form value to transmit information to the end handler. Sticky sessions: some load balancers can match a particular session to a server. If not using a sessionless approach, there are three modes of session management available in Microsoft Internet Information Services (IIS): - InProc: web sessions are stored in the web server s local memory. - OutProc: StateServer: session information is stored in memory on a separate server SQLServer: session information is shared across multiple servers. In an ASP.NET MVC 4 application, state information can be stored in the following locations: Cache, which is a memory pool stored on the server and shared across users Session, which is stored on the server and is unique for each user Cookies, which are stored on the client and passed with each HTTP request to the server QueryString, which is passed as part of the complete URL string Context.Items, which is part of the HttpContext and lasts only the lifetime of that request Profile, which is stored in a database and maintains information across multiple sessions Azure role lifecycle There are three types of roles in Windows Azure: 1. Web: to run IIS 2. Worker: to run middle-tier applications that don't use IIS 3. VM Startup tasks are available only for Web and Worker roles. They are defined in the Task element, which is a node in the Startup element of the ServiceDefinition.csdef file. A typical startup task is a console application or a batch file that can start one or more Windows PowerShell scripts. The procedure followed by Windows Azure when a role starts is the following: 1. 2. 3. 4. 6. 7. 8. The instance is marked as Starting. It will no longer receive traffic. Startup tasks are executed. The role host process is started and the site is created in IIS. The task calls the Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint.OnStart method. Azure sets the role status to Busy. A Web role can include initialization code in the ASP.NET Application_Start method instead of the OnStart method The instance is marked as Ready and traffic is routed to the instance. The task calls the Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint.Run method. This is equivalent to a Main method. The method must block indefinitely. Upon shutdown, the process calls the OnStop method. Caching strategies 1. Output caching a. Through action filters b. With donut caching, a server-side technology that caches an entire page other than the pieces of dynamic content ASP.NET MVC 5 Page 42
2. 3. 4. 5. b. With donut caching, a server-side technology that caches an entire page other than the pieces of dynamic content c. With donut hole caching, we cache only select portions of the page while keeping the rest of the page dynamic Distribution caching, with AppFabric Data caching, at the server side Application cache API HTTP cache HTTP modules and handlers In a line: "if we need information about the request prior to calling ASP.NET code, use a module. If we want special files to be handled differently, use a handler" The general application flow is: validation of the request --> URL mapping --> events --> HTTP handler --> events A module is developed to intercept and/or modify each request. And they can send the request towards different handlers. They must implement the interface IHttpModule and the following methods: - Void Init(HttpApplication): The class HttpApplication has 22 events that can be subscribed to and enables the module to work on the request in various stages of the process. - Void Dispose() To register a custom module, we must add it to the Web.config file. An ASP.NET HTTP handler is the process (frequently referred to as the "endpoint") that runs in response to a request made to an ASP.NET Web application. The most common handler is an ASP.NET page handler that processes.aspx files. Unlike modules, only one handler can process a request. A handler must implement the IHttpHandler interface and the following method: - Void ProcessRequest(HttpContext) Both modules and handlers can be made asynchronous. ASP.NET MVC 5 Page 43
Globalization and localization viernes, 21 de agosto de 2015 3:57 p. m. Globalization is to design an app so that it is usable my multiple cultures. Localization is the effort necessary to translate the data. If the app hasn't been globalized, the server sends responses in the server's culture. If the app has been globalized but not localized for the client's particular language, the same principle applies. The client requests a specific language by specifying the "Accept-Language" HTTP header. The server can adjust to this request by setting the web.config file, and the property Thread.CurrentThread.CurrentUICulture will be loaded with this information. 2 layers in localization: 1. Language (en) 2. Locale (us, uk) 3 ways to localize (can be combined): 1. Using resource files that contain the strings and media that differ for each culture. Then use the ResourceManager class. 2. Localize views (best to support non-western languages, e.g. Arabic) 3. Localize the client side through "jquery.globalize" The resource files (".resx") can be in a single application with the rest of the MVC app, or in a satellite assembly that improves performance, because the runtime will only load in memory the language needed. They can be generated like this: Al.exe /t:lib /embed:strings.es-ar.resources /culture:es-ar /out:myapp.es-ar.resources.dll ASP.NET MVC 5 Page 44