【.NET Framework】Back to ASP.NET Framework 1
Masui Masanori
Posted on September 2, 2020
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).
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
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
<%@ Application Codebehind="Global.asax.cs" Inherits="NetFrameworkSample.Global" Language="C#" %>
Global.asax.cs
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
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
...
[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
- GitHub - NLog/NLog.Web: NLog integration for ASP.NET & ASP.NET Core 1-3
- Tutorial · NLog/NLog Wiki · GitHub
Install
- NLog.Web ver.4.9.3
Configurations
To use NLog in ASP.NET Framework, I add configurations in Web.config.
Web.config
...
<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.
nlog.config
<?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
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.
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
namespace NetFrameworkSample.Products
{
public interface IProductsService
{
}
}
ProductsService.cs
namespace NetFrameworkSample.Products
{
public class ProductsService: IProductsService
{
}
}
UnityConfig.cs
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;
});
...
Inject
As same as "Microsoft.Extensions.DependencyInjection", Unity Container also use constructor injection.
ProductsController.cs
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".
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".
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).
Posted on September 2, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.