分类 编程 下的文章

在.Net Core 2.1下使用SkiaSharp进行图片处理

在.Net Core下,没有可以支持跨平台的Drawing类库,官网提供的Common.Drawing只能在Windows下使用,那么在.Net Core下该如何处理图片呢?其实有很多第三方提供了解决方案,而我比较喜欢用的是Mono团队提供的SkiaSharp,原因是稳定而且支持的也很好,性能上也还好。

一、SkiaSharp是什么?

1.Skia介绍

Skia是Google旗下的2D图形处理库,下面是援引百科中的词条:

skia是个2D向量图形处理函数库,包含字型、坐标转换,以及点阵图都有高效能且简洁的表现。不仅用于Google Chrome浏览器,新兴的Android开放手机平台也采用skia作为绘图处理,搭配OpenGL/ES与特定的硬件特征,强化显示的效果。

Skia官网中是这样介绍的:

Skia is an open source 2D graphics library which provides common APIs that work across a variety of hardware and software platforms. It serves as the graphics engine for Google Chrome and Chrome OS, Android, Mozilla Firefox and Firefox OS, and many other products.

2.SkiaSharp介绍

SkiaSharp故名思义,就是在.net下使用Skia API的库,是SkiaSharp是由mono团队开发并进行持续维护,至今已经多年了。目前的最新版本是1.60.3,当前支持.net下的:

  • .NET Standard 1.3

  • .NET Core

  • Tizen

  • Xamarin.Android

  • Xamarin.iOS

  • Xamarin.tvOS

  • Xamarin.watchOS

  • Xamarin.Mac

  • Windows Classic Desktop (Windows.Forms / WPF)

  • Windows UWP (Desktop / Mobile / Xbox / HoloLens)

SkiaSharp项目:https://github.com/mono/SkiaSharp

二、SkiaSharp的安装

可以通过nuget命令进行安装:

nuget install skiasharp

或者在要使用的项目下,打开nuget管理器,搜索skiasharp进行安装。

三、SkiaSharp的使用

1.生成缩略图

这里假设已经安装好SkiaSharp 1.60.3版本。
我们先把要缩略的原图加载到内存中:

using (var input = File.OpenRead($"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot/{pic}"))

这里的变量pic是图片的相对路径。
之后实例化一个SKManagedStream

using (var inputStream = new SKManagedStream(input))

最后,把inputStream加载到SKBitmap画布中

using (var original = SKBitmap.Decode(inputStream))

之后重新设置图片的尺寸,也就是完成缩略处理:

        using (var resized = original
           .Resize(new SKImageInfo(width, height), SKBitmapResizeMethod.Lanczos3))
        {
            if (resized == null) return "";
            using (var image = SKImage.FromBitmap(resized))
            {
                using (var output =
                       File.OpenWrite($"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot/{thumb_name}"))
                {
                    image.Encode(SKEncodedImageFormat.Png,quality)
                        .SaveTo(output);
                }
            }
        }

其中,变量widthheight分别为缩略图的宽度和高度,thumb_name为缩略图要保存的文件名,quality是质量,一般设置为75,或者是其他的自己觉得合适的值。
完整的例子:

using System.IO;
using Microsoft.Extensions.PlatformAbstractions;
using SkiaSharp;

        public static string MakeThumb(string pic,string thumb_dir, int width, int height)
        {
            const int quality = 75; //质量为75%
            using (var input = File.OpenRead($"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot/{pic}"))
            using (var inputStream = new SKManagedStream(input))
            using (var original = SKBitmap.Decode(inputStream))
            {
                string[] arr_pic = pic.Split('/');
                string filename = arr_pic[arr_pic.Length - 1];  //完整文件名
                string[] arr_filename = filename.Split('.');
                string ext = "";
                if (arr_filename.Length >= 2)
                {
                    ext = arr_filename[arr_filename.Length - 1];    //最后一个为扩展名
                }
                string thumb_name = $"{filename.Remove(filename.Length - ext.Length - 1)}-{width}x{height}.png";  //文件名,缩略图保存为png
                string save_dir = $"/attach/{thumb_dir}/thumb/{DateTime.Now.ToString("yyyy-MM-dd")}";
                string savepath = $"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot{save_dir}";
                if (!Directory.Exists(savepath))
                {
                    Directory.CreateDirectory(savepath);
                }
                string thumb_file = $"{save_dir}/{thumb_name}";
                using (var resized = original
                   .Resize(new SKImageInfo(width, height), SKBitmapResizeMethod.Lanczos3))
                {
                    if (resized == null) return "";
                    using (var image = SKImage.FromBitmap(resized))
                    {
                        using (var output =
                               File.OpenWrite($"{savepath}/{thumb_name}"))
                        {
                            image.Encode(SKEncodedImageFormat.Png,quality)
                                .SaveTo(output);
                        }
                    }
                }
                return thumb_file;
            }
        }

2.把指定的字体打印到图片上

其实图片的文字水印、图片验证码都可以从这个例子上扩充出来。
首先还是要安装SkiaSharp,之后,实例化SKImageInfo

var info = new SKImageInfo(width, height);

创建一个新的SKSurface

using (var surface = SKSurface.Create(info))

设置画布背景透明:

var canvas = surface.Canvas;
canvas.Clear(SKColors.White);

设置SKPaint的参数

       var paint = new SKPaint
        {
            Color = SKColors.Black,//颜色
            IsAntialias = true,//抗锯齿
            Style = SKPaintStyle.Fill,
            TextAlign = SKTextAlign.Center,//居中
            TextSize = 40F,//字号
            Typeface= SkiaSharp.SKTypeface.FromFile(fontpath, 0)//加载字体
        };

这里除了指定字体的路径之外,还可以使用SkiaSharp.SKTypeface.FromFamilyName("微软雅黑",SKTypefaceStyle.Bold)来通过字体名来设置要使用的字体;参数fontpath是字体的物理路径。

参数设置好之后,进行绘图:

var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize / 2);
canvas.DrawText(text, coord, paint);

最后,生成图片:

using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))

一个简单的例子:

using SkiaSharp;
using System.Linq;
        public static byte[] CreateImage(string fontpath, string text,float font_size=100)
        {
            var info = new SKImageInfo(1100, 480);
            using (var surface = SKSurface.Create(info))
            {
                var canvas = surface.Canvas;
                canvas.Clear(SKColors.White);
                
                var paint = new SKPaint
                {
                    Color = SKColors.Black,
                    IsAntialias = true,
                    Style = SKPaintStyle.Fill,
                    TextAlign = SKTextAlign.Center,
                    TextSize = font_size,
                    Typeface= SkiaSharp.SKTypeface.FromFile(fontpath, 0)
                };
                var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize) / 2);
                canvas.DrawText(text, coord, paint);                
                using (var image = surface.Snapshot())
                using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
                {
                    return data.ToArray();
                }
            }
        }

这个是指定的文字内容使用指定的字体直接显示到空白图片上,但是不支持文字换行。我们下面的例子是对上面的进行改进,支持文字换行:

public static byte[] CreateImage(string fontpath, string text,float font_size=100)
{
    //支持文字多行
    List<string> list = text.Split('\n').ToList();
    list.RemoveAll(x => { return string.IsNullOrEmpty(x.Trim()); });    //删除空行
    list.Reverse(); //顺序反转
    float line_height = 1.5F;   //行距
    float height = 480;
    if (list.Count * line_height*font_size >= height)
    {
        height = list.Count * line_height * font_size;
    }
    var info = new SKImageInfo(1100, (int)height);
    using (var surface = SKSurface.Create(info))
    {
        var canvas = surface.Canvas;
        canvas.Clear(SKColors.White);
        
        var paint = new SKPaint
        {
            Color = SKColors.Black,
            IsAntialias = true,
            Style = SKPaintStyle.Fill,
            TextAlign = SKTextAlign.Center,
            TextSize = font_size,
            Typeface= SkiaSharp.SKTypeface.FromFile(fontpath, 0)
        };

        int i = 0;
        list.ForEach(x =>
        {
            var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize * (list.Count - i) - paint.TextSize * i * 1.5F) / 2);
            canvas.DrawText(x.Trim(), coord, paint);
            i++;
            
        });

        using (var image = surface.Snapshot())
        using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
        {
            return data.ToArray();
        }
    }
}

测试地址:http://font.dwz.nz/fonts
源码:https://github.com/hongbai/FontsPrint

四、注意事项

如果要在Linux上使用,还需要同时上传libSkiaSharp.so文件,放到与SkiaSharp.dll同一文件夹下。libSkiaSharp.so文件可以在SkiaSharp的github上下载最新的发行版本,下载地址:https://github.com/mono/SkiaSharp/releases

五、总结

通过以上两个例子,我们可以发现,SkiaSharp的使用方法非常简单方便,而且各方面支持的都很不错,支持跨平台。功能上我暂时只在以上两个例子中使用,如果以后在其他方面用到的话,我会继续更新。代码写的丑,多包涵。

以上。

参考:
Skia Graphics Library
Skia 百度百科
SkiaSharp Github项目

.Net Core 2.1下,使用Oracle数据库

在.Net Core 2.1下,可以通过Dapper框架非常方便的使用Sql Server、MySQL、PostgreSQL等数据库,但是使用Oracle数据库就没那么方便了,比如执行存储过程的时候返回的游标,就没有对应的类型,另外还需要Oracle的驱动等等。
经过了几天的查阅资料,现在整理下在.Net Core 2.1下通过Dapper使用Oracle数据库的方法。
首先是连接数据库,方法与MySQL中的方法一样,见《在.Net Core 2.0中使用MySQL》,之后需要通过NuGet安装以下包:

  • Dapper

  • Dapper.Oracle

  • Oracle.ManagedDataAccess.Client

其中Oracle.ManagedDataAccess.Client是预发行版,需要勾选“包括预发行版”才能搜索到。
准备工作做好,下面是使用方法:
创建Oracle数据库链接:
var Conn = new OracleConnection(ConnString);

之后创建Oracle动态参数:
var parameters = new OracleDynamicParameters();

之后往动态参数中添加存储过程需要的参数:

parameters.Add("p_czlx", value: transfer.czlx);
parameters.Add("p_bzxx", value: transfer.bzxx);
parameters.Add("ResultStr", dbType: OracleMappingType.Varchar2, direction: ParameterDirection.Output);
parameters.Add("ResultCursor", dbType: OracleMappingType.RefCursor, direction: ParameterDirection.Output);

调用存储过程,得到返回的游标和出参:

var data = Conn.QueryFirstOrDefault<Models.UserMoney>("pkg_web.web_crj_gl", param: parameters, commandType: CommandType.StoredProcedure);
string res = parameters.Get<string>("ResultStr");   //出参

其中Models.UserMoney是游标对应的实体。
相对完整的代码:

using (var Conn = new OracleConnection(ConnString))
{
    var parameters = new OracleDynamicParameters();
    parameters.Add("p_czlx", value: transfer.czlx);
    parameters.Add("p_bzxx", value: transfer.bzxx);
    parameters.Add("ResultStr", dbType: OracleMappingType.Varchar2, direction: ParameterDirection.Output);
    parameters.Add("ResultCursor", dbType: OracleMappingType.RefCursor, direction: ParameterDirection.Output);

    var data = Conn.QueryFirstOrDefault<Models.UserMoney>("pkg_web.web_crj_gl", param: parameters, commandType: CommandType.StoredProcedure);
    string res = parameters.Get<string>("ResultStr");   //出参
    //对出参进行后续处理,省略

}

是不是很简单?
说下引用的这几个包的作用,Dapper就是ORM框架,Dapper.Oracle是针对Oracle重写的Dapper动态参数,Oracle.ManagedDataAccess.Client是Oracle官方提供的Oracle驱动,目前只有预发行版,还没有稳定版。
其实在第一次使用.Net Core+Oracle组合的时候,我也走了很多弯路,查到过好几篇博客提供的重写的OracleDynamicParameters方法,但是取出参的时候类型转换都有问题,本着能用现成的绝不自己手写的码畜精神,终于在gayhub(雾,github)上找到一条回复,提到了Dapper.Oracle,安装了之后果然好用。
希望这篇文章能帮到大家。

(完)

ASP.Net Core 2.0 在Linux下连接SQL Server数据库问题

在ASP.Net Core 2.0下,通过Dapper来使用SQL Server数据库,在Windows系统下完全正常,而部署到Linux服务器上会出现连不上数据库的情况,从日志里看,报下面的错误:

Connection Timeout Expired. The timeout period elapsed during the post-login phase. The connection could have timed out while waiting for server to complete the login process and respond; Or it could have timed out while attempting to create multiple active connections. The duration spent while attempting to connect to this server was - [Pre-Login] initialization=23; handshake=365; [Login] initialization=0; authentication=2; [Post-Login] complete=28022;

连接超时。开始的时候怀疑是防火墙的原因,检查了一下防火墙正常,而且通过telnet命令检查数据库的1433端口是通的,看来问题是出在.net core上。
通过百度和Google搜索相关的关键字,找到了一篇帖子:《Timeout Connecting to SQL Server instance from Linux》,说的是只有SQL Server 2008 及之前的版本会有这问题,SQL Server 2012及之后修复了这个问题。
检查了下自己的SQL数据库版本,是SQL Server 2008 R2 版的,正在此列。开了腾讯云的SQL Server云数据库连接测试,完全正常。

以上。

关于ASP.NET MVC中使用Forms验证的问题

表单验证(Forms验证)是一个基于票据(ticket-based)[也称为基于令牌(token-based)]的系统。这意味着当用户登录系统以后,他们得到一个包含基于用户信息的票据(ticket)。这些信息被存放在加密过的cookie里面,这些cookie和响应绑定在一起,因此每一次后续请求都会被自动提交到服务器。

当用户请求匿名用户无法访问的ASP.NET页面时,ASP.NET运行时验证这个表单验证票据是否有效。如果无效,ASP.NET自动将用户转到登录页面。这时就该由你来操作了。你必须创建这个登录页面并且验证由登录页面提交的凭证。如果用户验证成功,你只需要告诉ASP.NET架构验证成功(通过调用FormsAuthentication类的一个方法),运行库会自动设置验证cookie(实际上包含了票据)并将用户转到原先请求的页面。通过这个请求,运行库检测到验证cookie中包含一个有效票据,然后赋给用户对这个页面的访问权限。

下面,就是具体的实现。我们先写一个生成用户票据的方法:

//生成Token并保存到Cookies中
private void CreateToken(Models.User user)
{
    string json = JsonConvert.SerializeObject(user);
    FormsAuthentication.SetAuthCookie(user.UserName.Trim(), true, FormsAuthentication.FormsCookiePath);
    FormsAuthenticationTicket Ticket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddHours(12), false, json);
    Biz126.Cache.SetCookies.AddCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(Ticket));
}

其中Biz126.Cache.SetCookies.AddCookie是我自己封装的保存Cookie方法。
生成Token并保存到Cookie中的方法我们已经写好了,只要在登录成功之后直接调用这个方法就可以了。

下面是验证票据,验证票据,我们放在过滤器中进行验证。
新建AuthenticationAttribute类,继承ActionFilterAttribute,重写OnActionExecuting方法:

        /// <summary>
        /// 检查用户是否有该Action执行的操作权限
        /// </summary>
        /// <param name="actionContext"></param>
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            Models.ResultModel<object> result = new Models.ResultModel<object>();
            result.code = -401;
            result.message = "请登录后进行操作";
            result.status = false;
            //如果存在身份信息
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                filterContext.Response = filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized, result, "application/json");
            }
            else
            {                
                
                BLL.IManager manager = new BLL.Manage.Manager();
                result = manager.Detail();    //取当前登录的用户信息,进行其他的操作,比如判断有没有权限等,这里省略
                //。。。省略掉其他的操作
                
                if (!result.status)
                {
                    filterContext.Response = filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized, result, "application/json");
                    //filterContext.Result = redirect;
                }
            }
        }

之后,在要在需要用户登录的Action上面,加上[Authentication]就可以了,也可以新加一个控制器,如BaseWebApiController,在这个控制器上加上[Authentication],其他的控制器都继承BaseWebApiController,在不需要验证的Action上加上[AllowAnonymous]就可以了。
下面是通过票据取得用户信息:

            if (HttpContext.Current.Request.IsAuthenticated)//是否通过身份验证
            {
                HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];//获取cookie
                FormsAuthenticationTicket Ticket = FormsAuthentication.Decrypt(authCookie.Value);//解密
                string json = Ticket.UserData;//反序列化
                Models.Models.User user = new Models.User();
                try
                {
                    user = JsonConvert.DeserializeObject<Models.User>(json);
                    result.data = user;
                    result.message = "success";
                    result.status = true;
                }
                catch
                {

                }

            }

还需要在web.config中增加配置:

  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Users/Login" timeout="2880" />
    </authentication>
  </system.web>

到这里,其本上都已经完成了,但是你会发现,在IE上,会有很多用户登录的时候验证不通过的情况,如果记录日志,会发现HttpContext.Current.Request.IsAuthenticated==false
HttpContext.Current.Request.User为空
而且这种情况只有在IE下才会出现,其他的现代浏览器比如Chrome、Firefox等都很正常。
通过网络搜索,大部分都没给出答案来。其他把配置按下面的方法修改,就可以解决这个问题:

  <system.web>
    <authentication mode="Forms">
      <forms cookieless="UseCookies" loginUrl="~/Users/Login" timeout="2880" />
    </authentication>
    <authorization>
      <allow users="*" />
    </authorization>
  </system.web>

或者是打开服务器的IIS,按下面的步骤修改:
IIS的“身份证验证”
1.打开IIS,选择自己的站点,之后双击IIS中的“身份验证”功能
设置Forms身份验证
2.选中Forms身份验证,点击右侧操作区的“编辑”菜单,如果没有启用请先点击“启用”
Forms身份验证的默认设置
3.这是Forms身份验证的默认设置,我们需要改动一下
修改之后的Forms身份验证设置
4.按这里修改一下,就可以了。

以上。

ASP.NET Core 2.0下使用log4net记录文件日志

我们知道log4net的日志功能非常强大,而使用方法也比较复杂;在ASP.NET Core 2.0下,可以通过一个第三方的扩展方法来降低我们的使用难度,具体使用方法如下:
我们先新建一个自己的静态类Log4Net,用于之后调用记录日志:

    public static class Log4Net
{
    private static readonly log4net.ILog log =
    log4net.LogManager.GetLogger(typeof(Log4Net));

    static void SetConfig()
    {
        XmlDocument log4netConfig = new XmlDocument();
        log4netConfig.Load(File.OpenRead("log4net.config"));

        var repo = log4net.LogManager.CreateRepository(
            Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));

        log4net.Config.XmlConfigurator.Configure(repo, log4netConfig["log4net"]);
    }

    /// <summary>
    /// 信息
    /// </summary>
    /// <param name="Message"></param>
    public static void LogInfo(string Message)
    {
        if (!log.IsInfoEnabled)
            SetConfig();
        log.Info(Message);
    }

    /// <summary>
    /// 信息
    /// </summary>
    /// <param name="Message"></param>
    /// <param name="ex"></param>
    public static void LogInfo(string Message, Exception ex)
    {
        if (!log.IsInfoEnabled)
            SetConfig();
        log.Info(Message, ex);
    }

    /// <summary>
    /// 错误日志
    /// </summary>
    /// <param name="Message"></param>
    public static void ErrorInfo(string Message)
    {
        if (!log.IsErrorEnabled)
            SetConfig();
        log.Error(Message);
    }

    /// <summary>
    /// 错误日志
    /// </summary>
    /// <param name="Message"></param>
    /// <param name="ex"></param>
    public static void Error(Exception ex)
    {
        if (!log.IsInfoEnabled)
            SetConfig();
        log.Error("异常", ex);
    }

    /// <summary>
    /// 错误日志
    /// </summary>
    /// <param name="Message"></param>
    /// <param name="ex"></param>
    public static void ErrorInfo(string Message, Exception ex)
    {
        if (!log.IsErrorEnabled)
            SetConfig();
        log.Error(Message, ex);
    }

    /// <summary>
    /// Debug日志
    /// </summary>
    /// <param name="Message"></param>
    public static void DebugInfo(string Message)
    {
        if (!log.IsDebugEnabled)
            SetConfig();
        log.Debug(Message);
    }

    /// <summary>
    /// Debug日志
    /// </summary>
    /// <param name="Message"></param>
    /// <param name="ex"></param>
    public static void DebugInfo(string Message, Exception ex)
    {
        if (!log.IsDebugEnabled)
            SetConfig();
        log.Debug(Message, ex);
    }

    /// <summary>
    /// 警告
    /// </summary>
    /// <param name="Message"></param>
    public static void WarnInfo(string Message)
    {
        if (!log.IsWarnEnabled)
            SetConfig();
        log.Warn(Message);
    }

    /// <summary>
    /// 警告
    /// </summary>
    /// <param name="Message"></param>
    /// <param name="ex"></param>
    public static void WarnInfo(string Message,Exception ex)
    {
        if (!log.IsWarnEnabled)
            SetConfig();
        log.Warn(Message,ex);
        
    }

    /// <summary>
    /// 致命错误
    /// </summary>
    /// <param name="Message"></param>
    public static void FataInfo(string Message)
    {
        if (!log.IsFatalEnabled)
            SetConfig();
        log.Fatal(Message);
    }

    /// <summary>
    /// 致命错误
    /// </summary>
    /// <param name="Message"></param>
    /// <param name="ex"></param>
    public static void FataInfo(string Message,Exception ex)
    {
        if (!log.IsFatalEnabled)
            SetConfig();
        log.Fatal(Message, ex);
    }

该类下需要通过NuGet安装下面几个扩展:

  1. Microsoft.Extensions.Logging

  2. Microsoft.Extensions.Logging.Log4Net.AspNetCore

  3. log4net

之后log4net.config配置文件内容:

<log4net>
    <appender name="Console" type="log4net.Appender.ConsoleAppender">
        <layout type="log4net.Layout.PatternLayout">
            <!-- Pattern to output the caller's file name and line number -->
            <conversionPattern value="%5level [%thread] - STACK: %exception{stacktrace} - MESSAGE: %message%newline" />
        </layout>
    </appender>

    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
        <!--<file value="Log4Net" />
        <appendToFile value="true" />
    <rollingStyle value="Date" />
    <datePattern value="yyyyMMdd&quot;.log&quot;" />
        <maximumFileSize value="100KB" />
        <maxSizeRollBackups value="2" />-->
    <param name="File" value="logfile/" />
    <param name="AppendToFile" value="true" />
    <param name="RollingStyle" value="Date" />
    <param name="DatePattern" value="yyyyMMdd&quot;.log&quot;" />
    <param name="StaticLogFileName" value="false" />

        <layout type="log4net.Layout.PatternLayout">
            <!--<conversionPattern value="%level %thread - STACK: %exception{stacktrace} - MESSAGE: %message%newline" />-->
      <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
        </layout>
    </appender>

    <root>
        <level value="ALL" />
        <appender-ref ref="Console" />
        <appender-ref ref="RollingFile" />
    </root>
</log4net>

最后,修改Startup.cs文件的Configure方法,增加新参数如下:

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

在Configure方法中,添加:

loggerFactory.AddLog4Net();

完整如下:

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            loggerFactory.AddLog4Net();

            app.UseStaticFiles();

            app.UseMvc();
        }

测试:
我们写个测试的来看看,在Program类的静态方法中,添加段代码测试一下:

        public static void Main(string[] args)
        {
            Logger.Log4Net.LogInfo("test测试");

            try
            {
                int a = 5;
                int b = 1 / (a - 5);
            }
            catch (Exception e)
            {
                Logger.Log4Net.ErrorInfo("异常信息", e);
            }
            BuildWebHost(args).Run();
        }

运行之后,我们会在根目录下的logfile文件夹中,看到出现了一个日志文件:20180513.log
打开,内容如下:

2018-05-13 22:43:12,039 [1] INFO  Biz126.Logger.Log4Net - test测试
2018-05-13 22:43:12,930 [1] ERROR Biz126.Logger.Log4Net - 异常信息
System.DivideByZeroException: Attempted to divide by zero.
   at Biz126.WebAPI.Program.Main(String[] args) in D:\Items\Log测试\Biz126.WebAPI\Program.cs:line 23
2018-05-13 22:43:18,274 [5] INFO  Microsoft.AspNetCore.Hosting.Internal.WebHost - Request starting HTTP/1.1 GET http://localhost:65176/api/values  
2018-05-13 22:43:18,753 [5] INFO  Microsoft.AspNetCore.Hosting.Internal.WebHost - Request finished in 479.9045ms 404 

符合预期,以上。

分类

最新文章

最近回复

  • 老徐: 已经加上了,抱歉才看到
  • 青山: 某种原因,暂停友链,抱歉。
  • 搬瓦工: 朋友 交换链接吗
  • 飞刀说: 名称:飞刀说 描述:...
  • 青山: 计划搬迁到腾讯云,正...
  • 河边的飞刀: 网站名称:飞刀说 网...
  • 老徐: 具体要哪个呢?
  • 老徐: 是不是有点老?
  • 青山: 哇,林志炫
  • 老白: 哇,这改的可以,能不...

归档

标签云

C# .net core asp.net 情感 SQL mongodb sql server EasyUI 安全 激活 linux 身份验证 https typecho .net sql注入 kms MVC IIS 高并发 IE 坑爹 服务器 mysql Oracle Combobox Datagrid 口语 数据抓取

其它