【干货】ASP.NET Core 实战

点击上方“程序员大咖”,选择“置顶公众号”

关键时刻,第一时间送达!640?640?wx_fmt=gif


来源: SportSky

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 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<T>(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<T>(config.GetSection(key))
> 
>             .BuildServiceProvider()
> 
>             .GetService<IOptions<T>>()
> 
>             .Value;
> 
>         return appconfig;
> 
>     }
> 
> }

> /// <summary>
> 
> /// 读取配置文件
> 
> /// </summary>
> 
> /// <returns></returns>
> 
> [HttpGet]
> 
> public dynamic JsonConfig()
> 
> {
> 
>     var jsonStr = JsonConfigurationHelper.GetAppSettings<ConfigDTO>("config");
> 
>     return Ok(jsonStr);
> 
> }
> 
> /// <summary>
> 
> /// 实体类
> 
> /// </summary>
> 
> public class ConfigDTO
> 
> {
> 
>     public dynamic name { get; set; }
> 
> }

> {
> 
>   "config": {
> 
>     "name": "Core.Api"
> 
>   }
> 
> }

截图看效果

640?wx_fmt=png


五、程序集批量依赖注入

我们都知道依赖注入主要是为了方便解耦,解除应用程序之间的依赖关系,在我看来DI、IOC这两者差不多是一样的,DI是从应用程序的角度而IOC是从容器的角度,它们主要是对同一件事情的不同角度的描述。

然而,,,,,,当我们项目业务比较多的时候,如果要实现多个业务的注入,通常方法是手动一个个的添加注入,这样可能有点太繁琐,所以就想到了利用反射实现批量注入,,,,,,

帮助类

> public class RuntimeHelper
> 
> {
> 
>     /// <summary>
> 
>     /// 获取项目程序集,排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包
> 
>     /// </summary>
> 
>     /// <returns></returns>
> 
>     public static IList<Assembly> GetAllAssemblies()
> 
>     {
> 
>         var list = new List<Assembly>();
> 
>         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<Type> GetAllTypes()
> 
>     {
> 
>         var list = new List<Type>();
> 
>         foreach (var assembly in GetAllAssemblies())
> 
>         {
> 
>             var typeInfos = assembly.DefinedTypes;
> 
>             foreach (var typeInfo in typeInfos)
> 
>             {
> 
>                 list.Add(typeInfo.AsType());
> 
>             }
> 
>         }
> 
>         return list;
> 
>     }
> 
>     public static IList<Type> GetTypesByAssembly(string assemblyName)
> 
>     {
> 
>         var list = new List<Type>();
> 
>         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
> 
> {
> 
>     /// <summary>
> 
>     /// 用DI批量注入接口程序集中对应的实现类。
> 
>     /// </summary>
> 
>     /// <param name="service"></param>
> 
>     /// <param name="interfaceAssemblyName"></param>
> 
>     /// <returns></returns>
> 
>     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;
> 
>     }
> 
>     /// <summary>
> 
>     /// 用DI批量注入接口程序集中对应的实现类。
> 
>     /// </summary>
> 
>     /// <param name="service"></param>
> 
>     /// <param name="interfaceAssemblyName">接口程序集的名称(不包含文件扩展名)</param>
> 
>     /// <param name="implementAssemblyName">实现程序集的名称(不包含文件扩展名)</param>
> 
>     /// <returns></returns>
> 
>     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();
> 
>         }
> 
> }

640?wx_fmt=png

六、使用NLog写入文件日志

新建配置文件命名为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">
> 
>   <targets>
> 
> <!--写入文件-->
> 
>     <target
> 
>      xsi:type="File"
> 
>      name="DebugFile"
> 
>      fileName="Logs\Debug\${shortdate}.log"
> 
>      layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}异常信息:${exception}${newline}==============================================================${newline}" >
> 
>     </target>
> 
>     <target 
> 
>       xsi:type="File" 
> 
>       name="InfoFile" 
> 
>       fileName="Logs\Info\${shortdate}.log"
> 
>       layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}异常信息:${exception}${newline}==============================================================${newline}" >
> 
>     </target>
> 
>     <target 
> 
>       xsi:type="File" 
> 
>       name="ErrorFile" 
> 
>       fileName="Logs\Error\${shortdate}.log"
> 
>       layout="日志时间:${longdate}${newline}日志来源:${callsite}${newline}日志级别:${uppercase:${level}}${newline}消息内容:${message}${newline}异常信息:${exception}${newline}==============================================================${newline}" >
> 
>     </target>    
> 
>   <rules>
> 
>     <logger name="FileLogger" minlevel="Debug" maxLevel="Debug" writeTo="DebugFile" />
> 
>     <logger name="FileLogger" minlevel="Info" maxLevel="Info" writeTo="InfoFile" />
> 
>     <logger name="FileLogger" minlevel="Error" maxLevel="Error" writeTo="ErrorFile" />
> 
>   </rules>
> 
> </nlog>

在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");
> 
>         }
> 
>         /// <summary>
> 
>         /// 写入文件日志
> 
>         /// </summary>
> 
>         /// <returns></returns>
> 
>         [HttpGet]
> 
>         public dynamic WriteLogToFile()
> 
>         {
> 
>             _logger.Info("写入Info文件");
> 
>             _logger.Debug("写入Debug文件");
> 
>             _logger.Error("写入Error文件");
> 
>             return Ok();
> 
>         }
> 
> }

七、使用NLog写入数据库日志

添加依赖项:Microsoft.Extensions.Logging和NLog.Extensions.Logging

新建配置文件命名为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">
> 
>   <targets>
> 
>     <!--写入数据库-->
> 
>     <target xsi:type="Database" name="Database"
> 
>             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)">
> 
>       <!--日志来源-->
> 
>       <parameter name="@origin" layout="${callsite}"/>
> 
>       <!--日志等级-->
> 
>       <parameter name="@logLevel" layout="${level}"/>
> 
>       <!--日志消息-->
> 
>       <parameter name="@message" layout="${message}"/>
> 
>       <!--异常信息-->
> 
>       <parameter name="@exception" layout="${exception}" />
> 
>       <!--堆栈信息-->
> 
>       <parameter name="@stackTrace" layout="${stacktrace}"/>
> 
>       <!--自定义消息内容-->
> 
>       <parameter name="@desc" layout="${event-context:item=Desc}"/>
> 
>     </target>
> 
>   </targets>
> 
>   <rules>
> 
>     <logger name="DbLogger" levels="Trace,Debug,Info,Error"  writeTo="Database"/>
> 
>   </rules>
> 
> </nlog>

同第六项代码一样,也是在Configure方法设置,写入日志到数据库

> /// <summary>
> 
> /// 将日志写入数据库
> 
> /// </summary>
> 
> /// <returns></returns>
> 
> [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

640?wx_fmt=png

八、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 - 规则匹配时日志应该被写入的一系列目标,由逗号分隔。

目前只整理了这些,后续会持续更新到这里面,如有不合理的地方,请大家加以斧正、共同进步。

640?wx_fmt=gif640?【点击成为源码大神】

▼点击「阅读原文」进入程序员商城

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值