:::: MENU ::::

Tuesday, July 19, 2016

Updated May 22, 2016: Updated to match component invocations changes in ASP.NET Core RC2 / RTM
In previous versions of MVC, we used Child Actions to build reusable components / widgets that consisted of both Razor markup and some backend logic. The backend logic was implemented as a controller action and typically marked with a [ChildActionOnly] attribute. Child actions are extremely useful but as some have pointed out, it is easy to shoot yourself in the foot.
Child Actions do not exist in ASP.NET Core MVC. Instead, we are encouraged to use the new View Component feature to support this use case. Conceptually, view components are a lot like child actions but they are a lighter weight and no longer involve the lifecycle and pipeline related to a controller. Before we get into the differences, let’s take a look at a simple example.

A simple View Component

View components are made up of 2 parts: A view component class and a razor view.
To implement the view component class, inherit from the base ViewComponent and implement an Invoke or InvokeAsync method. This class can be anywhere in your project. A common convention is to place them in a ViewComponents folder. Here is an example of a simple view component that retrieves a list of articles to display in a What’s New section.
namespace MyWebApplication.ViewComponents
{
    public class WhatsNewViewComponent : ViewComponent
    {
        private readonly IArticleService _articleService;

        public WhatsNewViewComponent(IArticleService articleService)
        {
            _articleService = articleService;
        }

        public IViewComponentResult Invoke(int numberOfItems)
        {
            var articles = _articleService.GetNewArticles(numberOfItems);
            return View(articles);
        }
    }
}
Much like a controller action, the Invoke method of a view component simply returns a view. If no view name is explicitly specified, the defaultViews\Shared\Components\ViewComponentName\Default.cshtml is used. In this case,Views\Shared\Components\WhatsNew\Default.cshtml. Note there are a ton of conventions used in view components. I will be covering these in a future blog post.
Views\Shared\Components\WhatsNew\Default.cshtml
@model IEnumerable<Article>

<h2>What's New</h2>
<ul>
@foreach (var article in Model)
{
    <li><a asp-controller="Article" 
           asp-action="View" 
           asp-route-id="@article.Id">@article.Title</a></li>
}
</ul>
To use this view component, simply call @Component.InvokeAsync from any view in your application. For example, I added this to the Home/Index view:
Views\Home\Index.cshtml
<div class="col-md-3">
    @await Component.InvokeAsync("WhatsNew", new { numberOfItems = 3})
</div>
The first parameter to @Component.InvokeAsync is the name of the view component. The second parameter is an object specifying the names and values of arguments matching the parmeters of the Invoke method in the view component. In this case, we specified a single int namednumberOfItems, which matches the Invoke(int numberOfItems) method of the WhatsNewViewComponent class.
What's New View Component

How is this different?

So far this doesn’t really look any different from what we had with Child Actions. There are however some major differences here.

No Model Binding

With view components, parameters are passed directly to your view component when you call @Component.Invoke() or@Component.InvokeAsync() in your view. There is no model binding needed here since the parameters are not coming from the HTTP request. You are calling the view component directly using C#. No model binding means you can have overloaded Invoke methods with different parameter types. This is something you can’t do in controllers.

No Action Filters

View components don’t take part in the controller lifecycle. This means you can’t add action filters to a view component. While this might sound like a limitation, it is actually an area that caused problems for a lot of people. Adding an action filter to a child action would sometimes have unintended consequences when the child action was called from certain locations.

Not reachable from HTTP

A view component never directly handles an HTTP request so you can’t call directly to a view component from the client side. You will need to wrap the view component with a controller if your application requires this behaviour.

What is available?

Common Properties

When you inherit from the base ViewComponent class, you get access to a few properties that are very similar to controllers:
[ViewComponent]
public abstract class ViewComponent
{
    protected ViewComponent();
    public HttpContext HttpContext { get; }
    public ModelStateDictionary ModelState { get; }
    public HttpRequest Request { get; }
    public RouteData RouteData { get; }
    public IUrlHelper Url { get; set; }
    public IPrincipal User { get; }
    
    [Dynamic]    
    public dynamic ViewBag { get; }
    [ViewComponentContext]
    public ViewComponentContext ViewComponentContext { get; set; }
    public ViewContext ViewContext { get; }
    public ViewDataDictionary ViewData { get; }
    public ICompositeViewEngine ViewEngine { get; set; }

    //...
}
Most notably, you can access information about the current user from the User property and information about the current request from theRequest property. Also, route information can be accessed from the RouteData property. You also have the ViewBag and ViewData. Note that the ViewBag / ViewData are shared with the controller. If you set ViewBag property in your controller action, that property will be available in any ViewComponent that is invoked by that controller action’s view.

Dependency Injection

Like controllers, view components also take part in dependency injection so any other information you need can simply be injected to the view component. In the example above, we injected the IArticleService that allowed us to access articles form some remote source. Anything that you could inject into a controller can also be injected into a view component.

Wrapping it up

View components are a powerful new feature for creating reusable widgets in ASP.NET Core MVC. Consider using View Components any time you have complex rendering logic that also requires some backend logic.

Monday, July 4, 2016

If you developed professional Web applications using ASP.NET MVC, you are probably familiar with Dependency Injection. Dependency Injection (DI) is a technique to develop loosely coupled software systems. ASP.NET MVC didn't include any inbuilt DI framework and developers had to resort to some external DI framework. Luckily, ASP.NET Core 1.0 introduces a DI container that can simplify your work. This article introduces you to the DI features of ASP.NET Core 1.0 so that you can quickly use them in your applications.
Note: This article is based on RC2 of ASP.NET Core 1.0. Make sure to install RC2 before you follow the examples discussed in this article. Please follow this link for more details about usingDependency Injection in ASP.NET Core 1.0.
To understand how Dependency Injection works in ASP.NET Core 1.0, you will build a simple application. So, begin by creating a new ASP.NET Core 1.0 Web application by using an Empty project template.
"dependencies": {
   "Microsoft.NETCore.App": {
      "version": "1.0.0-rc2-3002702",
      "type": "platform"
   },

    
   "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
   "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
   },
   "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
   "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
   "Microsoft.AspNetCore.StaticFiles": "1.0.0-rc2-final",


   "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0-rc2-final",
   "Microsoft.EntityFrameworkCore.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
   },


   "Microsoft.Extensions.Configuration.EnvironmentVariables":
      "1.0.0-rc2-final",
   "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",


   "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
   },
   "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
      "version": "1.0.0-preview1-final",
      "type": "build"
   }
}
Make sure to restore packages by right-clicking the References folder and selecting Restore Packages from the shortcut menu.
Then, create a DIClasses folder under the project root folder. Add an interface named IServiceType to the DIClasses folder. A type that is to be injected is called a service type. The IServiceType interface will be implemented by the service type you create later. The IServiceType interface is shown below:
public interface IServiceType
{
   string GetGuid();
}

The IServiceType interface contains a single method—GetGuid(). As the name suggests, an implementation of this method is supposed to return a GUID to the caller. In a realistic case, you can have any application-specific methods here.
Then, add a MyServiceType class to the Core folder and implement IServiceType in it. The MyServiceType class is shown below:
public class MyServiceType:IServiceType
{
   private string guid;

   public MyServiceType()
   {
      this.guid = Guid.NewGuid().ToString();
   }

   public string GetGuid()
    {
      return this.guid;
   }
}
The MyServiceType class implements an IServiceType interface. The class declares a private variable—guid—that holds a GUID. The constructor generates a new GUID using the Guid structure and assigns it to the guid private variable. The GetGuid() method simply returns the GUID to the caller. So, every object instance of MyServiceType will have its own unique GUID. This GUID will be used to understand the working of the DI framework as you will see later.
Now, open the Startup.cs file and modify it as shown below:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
   services.AddScoped();
}

public void Configure(IApplicationBuilder app)
{
   app.UseStaticFiles();
   app.UseMvc(routes =>
   {
      routes.MapRoute(
         name: "default",
         template: "{controller=Home}/
            {action=Index}/{id?}");
   });
}
Notice the line shown in bold letters. This is how you register a service type with the ASP.NET Core DI container. The AddScoped() method is a generic method and you mention the interface on which the service type is based (IServiceType) and a concrete type (MyServiceType) whose object instance is to be injected.
A type injected with AddScoped() has a lifetime of the current request. That means each request gets a new object of MyServiceType to work with. Let's test this by injecting MyServiceType into a controller.
Proceed by adding HomeController and Index view to the respective folders. Then, modify the HomeController as shown below:
public class HomeController : Controller
{
       
   private IServiceType obj;

   public HomeController(IServiceType obj)
   {
      this.obj = obj;
   }

   public IActionResult Index()
   {
      ViewBag.Guid = obj.GetGuid();
      return View();
   }
}
The constructor of the HomeController accepts a parameter of IServiceType. This parameter will be injected by the DI framework for you. Remember that, for the DI to work as expected, a type must be registered with the DI container (as discussed earlier).
The IServiceType injected by the DI framework is stored in a private variable—obj—for later use. The Index() action calls the GetGuid() method on MyServiceType object and stores the GUID in ViewBag's Guid property. The Index view simply outputs this GUID as shown below:

@ViewBag.Guid

Now, run the application and you should see something like this:
Refresh the browser window a few times to simulate multiple requests. You will observe that a new GUID is displayed every time. This confirms the working of AddScoped() as discussed previously.
There are two more methods that can be used to control the lifetime of the injected object—AddTransient() and AddSingleton(). A service registered using AddTransient() behaves such that every request for an object gets a new object instance. So, if a single HTTP request requests a service type twice, two separate object instances will be injected. A service registered using AddSingleton() behaves such that all the requests to a service are served by a single object instance. Let's test these two methods, one by one.
Modify Startup.cs as shown below:
public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc();
   services.AddTransient();
}
In this case, you used the AddTransient() method to register the service type. Now, modify the HomeController like this:
public class HomeController : Controller
{
       
   private IServiceType obj1;
   private IServiceType obj2;

   public HomeController(IServiceType obj1,IServiceType obj2)
   {
      this.obj1 = obj1;
      this.obj2 = obj2;
   }

   public IActionResult Index()
   {
      ViewBag.Guid1 = obj1.GetGuid();
      ViewBag.Guid2 = obj2.GetGuid();
      return View();
   }
}
This time, the HomeController has two parameters of IServiceType. This is done just to simulate two requests to the same service type. The GUIDs returned by both the object instances are stored in the ViewBag. If you output the GUIDs on the Index view, you will see this:
As you can see, the GUIDs are different within a single HTTP request, indicating that different object instances are getting injected into the controller. If you refresh the browser window, you will get different GUIDs each time. Now, modify Startup.cs and use AddScoped() again to register the type. Run the application again. Did you notice the difference? Now, both the constructor parameters point to the same object instance, as confirmed by the GUIDs.
Now, change Startup.cs to use the AddSingleton() method:
public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc();
   services.AddSingleton();
}
Also, make corresponding changes to the HomeController (it will now have just one parameter) and the Index view. If you run the application and refresh the browser as before, you will observe that for all the requests the same GUID is displayed, confirming the singleton mode.
oday we are sharing the final release of Visual Studio 2015 Update 3, Team Foundation Server 2015 Update 3, and .NET Core and ASP.NET Core 1.0.
I’m going to start with .NET Core and ASP.NET Core. If you’ve not been following the .NET blog or the WebDev blog, .NET Core is a cross-platform, open source, and modular .NET platform for creating modern web apps, microservices, libraries and console applications that run on Windows, Mac, and Linux. This release includes the runtime and libraries for .NET Core and ASP.NET Core and a new set of command line tools, as well as Visual Studio and Visual Studio Code extensions that enable developers to work with .NET Core projects. The tooling will be at release quality with the next major release of Visual Studio, Visual Studio “15.”
Switching to VS Update 3, normally, I’d share some of the highlights of this release here, but over the past few months we’ve been working to improve our release notes and known issues so they are much more readable and approachable (and complete). So rather than using this post to talk about a bunch of the changes, I want to share a story about hunting down some memory issues in VS.
This is really a tale of two customers – both reasonably large and successful companies who’ve been using VS for many years. Both had reached out to us with saying they were having problems with sluggishness and stability when dealing with solution files containing 100s of projects and millions of files. One customer, for example, had a solution file with 500 projects (all .NET), which was making VS hang and crash from anywhere within five to 60 minutes of opening a solution. Another customer had a solution file with 200 projects (mostly .NET, but a handful of C++ projects). Though this project would load successfully, it was consuming a lot of CPU cycles, causing the IDE to be very sluggish while editing code, and the customer also experienced random crashes.
On the surface, these might look like very related issues. But they weren’t. As we talked with the customers and debugged their solutions, it became clear that the root causes were pretty different. Here are some of the things we learned and what we changed:
  • We had tuned the algorithm for releasing cached project information to one particular shape of solutions (basically mid-sized .NET-only solutions)
  • Some cached project information was simply retained for too long, regardless of the solution.
  • VS enabled high-impact features like full code scanning in all cases, rather than allowing users to select whether they wanted them on or not.
  • When VS would fire events aimed at multiple projects in a solution, VS wouldn’t properly batch them; it processed them one by one.
  • VS would sometimes promote metadata references to project-to-project (P2P) references for a better experience; however, for some customers (those with complex P2P reference chains, or with post-build steps that modify binaries), this was actually degrading performance.
These problems turned out to be quite complex, often involving engineers from five or six feature teams to diagnose and fix them. That took time – our time and, more importantly, the customers’ time. I want to take a second here to thank both of these customers (you know who you are) for their patience and willingness to let us take a look at their projects.
All of these fixes (and more) are in Update 3; please take a look at the release notes and known issues for the full list.
[Updated June 30th:  Thanks to some of you early adopters, we were able to fix or offer workarounds for some installation issues that were affecting a small percentage of users, including the inability to install Update 3 and not being able to create or load UWP projects.  Other fixes to other product issues are in the works and will be available soon.  Please refer to the known issues for details.]
To learn more about other related downloads, see the Downloads page. You can also access the bits and release notes right now on an Azure-hosted VM. You should be able to install this update on top of previous installations of Visual Studio 2015.
As always, we welcome your feedback. For problems, let us know via the Report a Problem option in Visual Studio. For suggestions, let us know through UserVoice.