【.NET Framework】Back to ASP.NET Framework 1
Tags: csharp, aspnetframework, dotnetframework
Published: 2020-09-02 12:34:18

## Intro
In my private programming, I usually use .NET Core.
But I also use .NET Framework in my work.

I want to write at least ASP.NET MVC is the same for .NET Core and the .NET Framework.

So I try ASP.NET Framework this time.

### Environments
* Visual Studio 2019 Community
* .NET Framework ver.4.8

### Base Project
I create a project with Empty template.
Because there are no any class files, so I can't even open the root page(localhost:59522).
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4ca31f1c4pmb38zqg2c5.jpg)

## Routing
I can define how to route by "RouteConfig.cs".
First, I add "ASP.NET MVC" with NuGet.

* ASP.NET MVC ver.5.2.7

As same as ASP.NET Core, I can use "Convention-Based Routing" and "Attribute-Based Routing".
Because I felt second one was easier to use, I choosed it.

#### RouteConfig.cs
```csharp
using System.Web.Mvc;
using System.Web.Routing;

namespace NetFrameworkSample
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            // Use Attribute-Based Routing
            routes.MapMvcAttributeRoutes();
        }
    }
}
```

### Use RouteConfig
Because it is not activated automatically, I create Global Application Class(asax) and add RouteConfig.

#### Global.asax
```xml
<%@ Application Codebehind="Global.asax.cs" Inherits="NetFrameworkSample.Global" Language="C#" %>
```

#### Global.asax.cs
```csharp
using System;
using System.Web.Mvc;
using System.Web.Routing;

namespace NetFrameworkSample
{
    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}
```

Although "Global.asax.cs" has many methods by default, I only use "Application_Start" in this time.

### Add a Controller class
Now I can use "Attribute-Based Routing".
So I add a Controller class and show "Hello World!".

#### ProductsController.cs
```csharp
using System.Web.Mvc;

namespace NetFrameworkSample.Controllers
{
    public class ProductsController: Controller
    {
        public ProductsController()
        {
        }
        [Route("")]
        public string GetMessage()
        {
            return "Hello world!";
        }
    }
}
```
### Starting with "/"
In "Route" attribute, I can't start with slash like "[Route("/")]" or I get an exception.
I got a little confused, because I don't get any exceptions in ASP.NET Core.

### Directory name
I add new route.

#### ProductsController.cs
```csharp
...
        [Route("Products")]
        public string GetProductsMessage()
        {
            return "Hello Products";
        }
    }
}
```
Of cource I can get "Hello Products" with "localhost:59522/Products".

And I add "Products" directory and "IProductService.cs" into it.
After that, I access "localhost:59522/Products" and get an exception.

It is as same as before I add "RouteConfig".

Because if there is a directory what is named the same name as route, ASP.NET Framework searches view files in the directory.

So I have to be careful the directory names.
(I also can set routes like "localhost:59522/Api/Products")

## Log (NLog)
I output log with NLog.

* [NLog](https://nlog-project.org/)
* [GitHub - NLog/NLog.Web: NLog integration for ASP.NET & ASP.NET Core 1-3](https://github.com/NLog/NLog.Web)
* [Tutorial · NLog/NLog Wiki · GitHub](https://github.com/NLog/NLog/wiki/Tutorial)

### Install
* NLog.Web ver.4.9.3

### Configurations
To use NLog in ASP.NET Framework, I add configurations in Web.config.

#### Web.config
```xml
...
  <system.webServer> 
    <modules runAllManagedModulesForAllRequests="true"> 
      <add name="NLog" type="NLog.Web.NLogHttpModule, NLog.Web" />
    </modules>
  </system.webServer>
</configuration>
```
And I add nlog.config as same as [.NET Core](https://dev.to/masanori_msl/net-core-play-with-console-app-268n).

#### nlog.config
```xml
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">

    <targets>
        <target xsi:type="Console" name="outputconsole"
            layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />

        <target xsi:type="File" name="outputfile" fileName="C:\tmp\logs\NetFrameworkSample\${date:format=yyyy}\${date:format=MM}\${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
    </targets>

    <rules>
        <logger name="*" minlevel="Debug" writeTo="outputconsole" />>
        <logger name="Microsoft.*" maxLevel="Info" final="true" />
        <logger name="*" minlevel="Debug" writeTo="outputfile" />
    </rules>
</nlog>
```
### Create instances
I can create an instance by "LogManager.GetCurrentClassLogger()".

#### ProductsController.cs
```csharp
using System.Web.Mvc;
using NLog;

namespace NetFrameworkSample.Controllers
{
    public class ProductsController: Controller
    {
        private readonly Logger _logger;
        public ProductsController()
        {
            _logger = LogManager.GetCurrentClassLogger();
        }
        [Route("")]
        public string GetMessage()
        {
            _logger.Debug("Hello");
            return "Hello world!";
        }
...
```

Now I can output logs like below.

```
2020-09-02 21:05:58.0307||DEBUG|NetFrameworkSample.Controllers.ProductsController|Hello |url: http://localhost/|action: 
```

## DI (Dependency Injection)
ASP.NET Framework doesn't have DI by default.

I use Unity Container in this time.

* [Welcome to Unity Container Documentation! | Unity Container](http://unitycontainer.org/)

I found I also could use "Microsoft.Extensions.DependencyInjection".
So in the future, I may try it.

### Install
* Unity.Container ver.5.11.8
* Unity.Mvc ver.5.11.1

### Register dependencies
#### IProductsService.cs
```csharp
namespace NetFrameworkSample.Products
{
    public interface IProductsService
    {
    }
}
```
#### ProductsService.cs
```csharp
namespace NetFrameworkSample.Products
{
    public class ProductsService: IProductsService
    {
    }
}
```

#### UnityConfig.cs
```csharp
using System;
using Unity;
using NetFrameworkSample.Products;

namespace NetFrameworkSample
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public static class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container =
          new Lazy<IUnityContainer>(() =>
          {
              var container = new UnityContainer();
              RegisterTypes(container);
              
              container.RegisterType<IProductsService, ProductsService>(TypeLifetime.Scoped);
              
              return container;
          });
...
```
* [Per Container Lifetime | Unity Container](http://unitycontainer.org/tutorials/lifetime/container.html)

### Inject
As same as "Microsoft.Extensions.DependencyInjection", Unity Container also use constructor injection.

#### ProductsController.cs
```csharp
using System.Web.Mvc;
using NetFrameworkSample.Products;

namespace NetFrameworkSample.Controllers
{
    public class ProductsController: Controller
    {
        private readonly IProductsService _product;
        public ProductsController(IProductsService product)
        {
            _product = product;
        }
...
```

### Register instance
When I want to inject specify instances like DbContext, I can use "RegisterInstance".

```csharp
var sample = new ProductsService();
container.RegisterInstance<IProductsService>(sample, InstanceLifetime.PerContainer);              
```

Though I can inject NLog instance. but I shouldn't do that.
Because all of the class names of "logger" becomes "UnityConfig".

### Type(Instance) lifetime
Unity Container has more types of lifetime controls than "Microsoft.Extensions.DependencyInjection".

* [Lifetime Management | Unity Container](http://unitycontainer.org/tutorials/lifetime/lifetime.html)

### Inject concrete classes
I can inject concrete classes without registration.
But their instances' life time is Transient.

So I must register explicit the classes what should be set other lifetime like DbContext(Scoped).