歡迎光臨
每天分享高質量文章

ASP.NET Core 實戰

來源: SportSky

鏈接:http://www.cnblogs.com/sportsky/p/9400419.html

序言

使用.NET Core,團隊可以更容易專註的在.net core上工作。比如核心類庫(如System.Collections)的更改仍然需要與.NET Framework相同的活力,但是ASP.NET Core或Entity Framework Core可以更輕鬆地進行實質性更改,而不受向後兼容性的限制。

.NET Core借鑒了.NET Framework的最佳實踐,並將軟體工程的最新進展結合在一起。

一、淺談Startup類

在ASP.NET Core應用程式中,使用一個按約定Startup命名的類Startup,在Program.cs中使用WebHostBuilderExtensions UseStartup 方法指定類,但通常使用系統預設的startup,可以通過startup的建構式進行依賴註入,startup類中必須包含Configure方法同時可以根據實際情況添加ConfigureServices方法,這兩個方法均在應用程式運行時被呼叫。Startup 類的 執行順序:構造 -> configureServices ->configure

ConfigureServices方法:主要用於服務配置,比如依賴註入(DI)的配置,使用時該方法必須在Configure方法之前

Configure方法:用於應用程式響應HTTP請求,通過向IApplicationBuilder實體添加中間件組件來配置請求管道

二、自定義路由

在Startup類的Configure方法配置

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

    if (env.IsDevelopment())

    {

        app.UseDeveloperExceptionPage();

    }

    #region 自定義路由配置

    app.UseMvc(routes =>

    {

        // 自定義路由

        routes.MapRoute(

          name: “default1”,

          template: “api/{controller}/{action}/{id?}”,

          defaults: new { controller = “Values”, action = “Index” });

        // 預設路由

        routes.MapRoute(

           name: “default”,

           template: “{controller}/{action}/{id?}”,

           defaults: new { controller = “Values”, action = “Index” });

    });

    #endregion

}

三、跨域設置

在Startup類的ConfigureServices方法配置

public void ConfigureServices(IServiceCollection services)

{

    #region 跨域設置

    services.AddCors(options =>

    {

        options.AddPolicy(“AppDomain”, builder =>

        {

            builder.AllowAnyOrigin() // Allow access to any source from the host

            .AllowAnyMethod()        // Ensures that the policy allows any method

            .AllowAnyHeader()        // Ensures that the policy allows any essay-header

            .AllowCredentials();     // Specify the processing of cookie

        });

    });

    #endregion

    services.AddMvc();

}

其中“AppDomain”這個名字是自定義的,大家可以根據自己的喜好定義不同的名字,配置完成之後,在控制器上面添加[EnableCors(“AppDomain”)]特性即可,如果要實現全域性的跨域設置,可以在Configure方法裡面配置app.UseCors(“AppDomain”),即能實現全域性的跨域設置

四、自定義讀取配置檔案信息

這裡是寫的一個公共方法去讀取配置檔案appsettings.json

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.Configuration.Json;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Options;

using System.IO;

public class JsonConfigurationHelper

{

    public static T GetAppSettings(string key,string path= “appsettings.json”) where T : class, new()

    {

        var currentClassDir = Directory.GetCurrentDirectory();

        IConfiguration config = new ConfigurationBuilder()

            .SetBasePath(currentClassDir)

            .Add(new JsonConfigurationSource { Path = path, Optional = false, ReloadOnChange = true })

            .Build();

        var appconfig = new ServiceCollection()

            .AddOptions()

            .Configure(config.GetSection(key))

            .BuildServiceProvider()

            .GetService>()

            .Value;

        return appconfig;

    }

}

///

/// 讀取配置檔案

///

///

[HttpGet]

public dynamic JsonConfig()

{

    var jsonStr = JsonConfigurationHelper.GetAppSettings(“config”);

    return Ok(jsonStr);

}

///

/// 物體類

///

public class ConfigDTO

{

    public dynamic name { get; set; }

}

{

  “config”: {

    “name”: “Core.Api”

  }

}

截圖看效果

五、程式集批量依賴註入

我們都知道依賴註入主要是為了方便解耦,解除應用程式之間的依賴關係,在我看來DI、IOC這兩者差不多是一樣的,DI是從應用程式的角度而IOC是從容器的角度,它們主要是對同一件事情的不同角度的描述。

然而,,,,,,當我們專案業務比較多的時候,如果要實現多個業務的註入,通常方法是手動一個個的添加註入,這樣可能有點太繁瑣,所以就想到了利用反射實現批量註入,,,,,,

幫助類

public class RuntimeHelper

{

    ///

    /// 獲取專案程式集,排除所有的系統程式集(Microsoft.***、System.***等)、Nuget下載包

    ///

    ///

    public static IList GetAllAssemblies()

    {

        var list = new List();

        var deps = DependencyContext.Default;

        var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != “package”);//排除所有的系統程式集、Nuget下載包

        foreach (var lib in libs)

        {

            try

            {

                var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));

                list.Add(assembly);

            }

            catch (Exception)

            {

                // ignored

            }

        }

        return list;

    }

    public static Assembly GetAssembly(string assemblyName)

    {

        return GetAllAssemblies().FirstOrDefault(assembly => assembly.FullName.Contains(assemblyName));

    }

    public static IList GetAllTypes()

    {

        var list = new List();

        foreach (var assembly in GetAllAssemblies())

        {

            var typeInfos = assembly.DefinedTypes;

            foreach (var typeInfo in typeInfos)

            {

                list.Add(typeInfo.AsType());

            }

        }

        return list;

    }

    public static IList GetTypesByAssembly(string assemblyName)

    {

        var list = new List();

        var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));

        var typeInfos = assembly.DefinedTypes;

        foreach (var typeInfo in typeInfos)

        {

            list.Add(typeInfo.AsType());

        }

        return list;

    }

    public static Type GetImplementType(string typeName, Type baseInterfaceType)

    {

        return GetAllTypes().FirstOrDefault(t =>

        {

            if (t.Name == typeName &&

                t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name))

            {

                var typeInfo = t.GetTypeInfo();

                return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType;

            }

            return false;

        });

    }

}

public static class ServiceExtension

{

    ///

    /// 用DI批量註入接口程式集中對應的實現類。

    ///

    ///

    ///

    ///

    public static IServiceCollection RegisterAssembly(this IServiceCollection service, string interfaceAssemblyName)

    {

        if (service == null)

            throw new ArgumentNullException(nameof(service));

        if (string.IsNullOrEmpty(interfaceAssemblyName))

            throw new ArgumentNullException(nameof(interfaceAssemblyName));

        var assembly = RuntimeHelper.GetAssembly(interfaceAssemblyName);

        if (assembly == null)

        {

            throw new DllNotFoundException($”the dll “{interfaceAssemblyName}” not be found”);

        }

        //過濾掉非接口及泛型接口

        var types = assembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType);

        foreach (var type in types)

        {

            var implementTypeName = type.Name.Substring(1);

            var implementType = RuntimeHelper.GetImplementType(implementTypeName, type);

            if (implementType != null)

                service.AddSingleton(type, implementType);

        }

        return service;

    }

    ///

    /// 用DI批量註入接口程式集中對應的實現類。

    ///

    ///

    /// 接口程式集的名稱(不包含檔案擴展名)

    /// 實現程式集的名稱(不包含檔案擴展名)

    ///

    public static IServiceCollection RegisterAssembly(this IServiceCollection service, string interfaceAssemblyName, string implementAssemblyName)

    {

        if (service == null)

            throw new ArgumentNullException(nameof(service));

        if (string.IsNullOrEmpty(interfaceAssemblyName))

            throw new ArgumentNullException(nameof(interfaceAssemblyName));

        if (string.IsNullOrEmpty(implementAssemblyName))

            throw new ArgumentNullException(nameof(implementAssemblyName));

        var interfaceAssembly = RuntimeHelper.GetAssembly(interfaceAssemblyName);

        if (interfaceAssembly == null)

        {

            throw new DllNotFoundException($”the dll “{interfaceAssemblyName}” not be found”);

        }

        var implementAssembly = RuntimeHelper.GetAssembly(implementAssemblyName);

        if (implementAssembly == null)

        {

            throw new DllNotFoundException($”the dll “{implementAssemblyName}” not be found”);

        }

        //過濾掉非接口及泛型接口

        var types = interfaceAssembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType);

        foreach (var type in types)

        {

            //過濾掉抽象類、泛型類以及非class

            var implementType = implementAssembly.DefinedTypes

                .FirstOrDefault(t => t.IsClass && !t.IsAbstract && !t.IsGenericType &&

                                     t.GetInterfaces().Any(b => b.Name == type.Name));

            if (implementType != null)

            {

                service.AddSingleton(type, implementType.AsType());

            }

        }

        return service;

    }

}

在Startupl類的ConfigureServices方法中添加

// This method gets called by the runtime. Use this method to add services to the container.

public void ConfigureServices(IServiceCollection services)

{

    #region 程式集批量依賴註入

    services.RegisterAssembly(“Core.BLL”);

    #endregion

    services.AddMvc();

}

呼叫(Ps:Core.BLL這個類庫裡面分別有一個接口IAccountService和一個類AccountService,AccountService類去繼承接口IAccountService並實現接口裡面的方法)

public interface IAccountService

{

    int GetLst();

}

public class AccountService: IAccountService

{

    public int GetLst()

    {

        return 1;

    }

}

public class ValuesController : Controller

{

        private readonly IAccountService _accountService;

        public ValuesController(IAccountService accountService)

        {

            _accountService = accountService;

        }

        [HttpGet]

        public dynamic GetAccount()

        {

            var result = this._accountService.GetLst();

            return Ok();

        }

}

六、使用NLog寫入檔案日誌

新建配置檔案命名為Nlog.config

 

    

   

     xsi:type=”File”

     name=”DebugFile”

     fileName=”LogsDebug${shortdate}.log”

     layout=”日誌時間:${longdate}${newline}日誌來源:${callsite}${newline}日誌級別:${uppercase:${level}}${newline}訊息內容:${message}${newline}異常信息:${exception}${newline}==============================================================${newline}” >

   

   

      xsi:type=”File” 

      name=”InfoFile” 

      fileName=”LogsInfo${shortdate}.log”

      layout=”日誌時間:${longdate}${newline}日誌來源:${callsite}${newline}日誌級別:${uppercase:${level}}${newline}訊息內容:${message}${newline}異常信息:${exception}${newline}==============================================================${newline}” >

   

   

      xsi:type=”File” 

      name=”ErrorFile” 

      fileName=”LogsError${shortdate}.log”

      layout=”日誌時間:${longdate}${newline}日誌來源:${callsite}${newline}日誌級別:${uppercase:${level}}${newline}訊息內容:${message}${newline}異常信息:${exception}${newline}==============================================================${newline}” >

   

   

 

   

   

   

 

在Startup類Configure方法中添加配置

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

{

    if (env.IsDevelopment())

    {

        app.UseDeveloperExceptionPage();

    }

    #region NLog配置

    loggerFactory.AddNLog(); // 添加NLog

    loggerFactory.ConfigureNLog($”{Directory.GetCurrentDirectory()}\Nlog.config”); // 添加Nlog.config配置檔案

    loggerFactory.AddDebug();

    #endregion

}

寫入日誌到檔案

public class ValuesController : Controller

{

        private readonly Logger _logger;

       

        public ValuesController()

        {

            _logger = LogManager.GetLogger(“FileLogger”);

        }

        ///

        /// 寫入檔案日誌

        ///

        ///

        [HttpGet]

        public dynamic WriteLogToFile()

        {

            _logger.Info(“寫入Info檔案”);

            _logger.Debug(“寫入Debug檔案”);

            _logger.Error(“寫入Error檔案”);

            return Ok();

        }

}

七、使用NLog寫入資料庫日誌

添加依賴項:Microsoft.Extensions.Logging和NLog.Extensions.Logging

新建配置檔案命名為Nlog.config

 

   

   

            connectionString=”Data Source=.;Initial Catalog=MyDb;Persist Security Info=True;User ID=sa;Password=123456″

            commandText=”insert into NLog_Log([CreateOn],[Origin],[LogLevel], [Message], [Exception],[StackTrace],[Desc]) values (getdate(), @origin, @logLevel, @message,@exception, @stackTrace,@desc)”>

      

     

     

     

     

     

     

     

     

     

     

     

     

   

 

 

   

 

同第六項代碼一樣,也是在Configure方法設置,寫入日誌到資料庫

///

/// 將日誌寫入資料庫

///

///

[HttpGet]

public dynamic WriteLogToDb()

{

    Logger _dblogger = LogManager.GetLogger(“DbLogger”);

    LogEventInfo ei = new LogEventInfo();

    ei.Properties[“Desc”] = “我是自定義訊息”;

    _dblogger.Info(ei);

    _dblogger.Debug(ei);

    _dblogger.Trace(ei);

    return Ok();

}

USE [MyDb]

GO

/****** Object:  Table [dbo].[NLog_Log]    Script Date: 08/09/2018 17:13:20 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [dbo].[NLog_Log](

    [ID] [int] IDENTITY(1,1) NOT NULL,

    [Origin] [nvarchar](500) NULL,

    [LogLevel] [nvarchar](500) NULL,

    [Message] [nvarchar](500) NULL,

    [Desc] [nvarchar](500) NULL,

    [Exception] [nvarchar](500) NULL,

    [StackTrace] [nvarchar](500) NULL,

    [CreateOn] [datetime] NULL

) ON [PRIMARY]

GO

八、Nlog標簽解讀

NLog的使用方式基本上和其它的Log庫差不多,用於輸出日誌的級別包括:Trace,Debug,Info,Warn,Error,Fatal

標簽

autoReload 修改配置檔案後是否允許自動加載無須重啟程式

throwExceptions 內部日誌系統丟擲異常

internalLogLevel 可選Trace|Debug|Info|Warn|Error|Fatal決定內部日誌的級別 Off 關閉

internalLogFile 把內部的除錯和異常信息都寫入指定檔案里

建議throwExceptions的值設為“false”,這樣由於日誌引發的問題不至於導致應用程式的崩潰。

標簽

區域定義了日誌的標的或者說輸出 ,,在這裡可以按需設置檔案名稱和格式,輸出方式。

name:自定義該target的名字,可供rule規則里使用

type: 定義型別,官方提供的可選型別有:

Chainsaw|ColoredConsole |Console |Database|Debug|Debugger|EventLog|File|LogReceiverService|Mail|Memory|MethodCall|Network |NLogViewer|Null |OutputDebugString|PerfCounter|Trace|WebService

不過常用的還是 File Database Colored Console Mail

layouts 用來規定佈局樣式,語法“${屬性}”,可以把背景關係信息插入到日誌中,更多佈局渲染器可參考https://github.com/nlog/NLog/wiki/Layout%20Renderers

標簽

各種規則配置在logger里

name – 記錄者的名字

minlevel – 最低級別

maxlevel – 最高級別

level – 單一日誌級別

levels – 一系列日誌級別,由逗號分隔。

writeTo – 規則匹配時日誌應該被寫入的一系列標的,由逗號分隔。

 

目前只整理了這些,後續會持續更新到這裡面,如有不合理的地方,請大家加以斧正、共同進步。



●編號139,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

Web開發

更多推薦18個技術類公眾微信

涵蓋:程式人生、演算法與資料結構、黑客技術與網絡安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

赞(0)

分享創造快樂