标签 .net core 下的文章

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 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 

符合预期,以上。

ASP.NET Core 2.0 WebAPI 跨域问题

关于 asp.net core 2.0 webapi的跨域,我们这里使用CORS来实现,不使用旧的JSONP,可以这样配置:
打开 Startup.cs文件,转到ConfigureServices(IServiceCollection services) 中,增加:

services.AddCors(options =>
{
    options.AddPolicy("AnyOrigin", builder =>
    {
        builder
            .AllowAnyOrigin()
            .AllowAnyMethod();
    });
});

再转到Configure(IApplicationBuilder app, IHostingEnvironment env)中,增加:

app.UseCors("AnyOrigin");

就可以开启CORS跨域了。
关于ASP.Net Core的CORS跨域问题详细的使用方法,请参考《Enable Cross-Origin Requests (CORS) in ASP.NET Core》一文。
下面测试一下:

<html>
    <head>
        
    </head>
    <body>
        
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
        <script>
            $(function(){
                $.ajax({
                    url:"http://domain/api/Mall/Category/List",
                    data:{id:1},
                    dataType:"json",
                    type:"post",
                    success:function(result){
                        console.log(result);
                    }
                });
            });
        </script>
    </body>
</html>

直接双击通过浏览器打开这个页面,可以看到,已经读到远程接口的数据了:
console
network
以上。

ASP.NET Core 2.0下使用Redis——基于CSRedis实现

前几天挖了个坑,今天就来填这个坑了。关于在ASP.NET Core 2.0下使用Redis的问题,目前StackExchange.Redis已经支持.Net Core 2.0了,而微软提供的Microsoft.Extensions.Caching.Redis.Core方法,也是对StackExchange.Redis的一种官方封装,是基于StackExchange.Redis的,但是大家反映StackExchange.Redis在.Net Core下高并发容易出现死锁问题,目前没有解决办法。
本例是基于CSRedis来实现的,CSRedis 是国外大神写的,经过少量修改,现已支持 .NETCore
使用方法,先新建一个Redis缓存的类库,我这里命名为:Biz126.RedisCache,在该类库下新增一个名为RedisHelper的Redis帮助类:

namespace Biz126.RedisCache
{
    public class RedisHelper : CSRedis.QuickHelperBase
    {
        public static IConfigurationRoot Configuration { get; internal set; }
        public static void InitializeConfiguration(IConfigurationRoot cfg)
        {
            Configuration = cfg;
            string ip, pass;
            if (!int.TryParse(Convert.ToString(cfg["Redis:port"]), out int port)) port = 6379;
            if (!int.TryParse(Convert.ToString(cfg["Redis:poolsize"]), out int poolsize)) poolsize = 50;
            if (!int.TryParse(Convert.ToString(cfg["Redis:database"]), out int database)) database = 0;
            ip = Convert.ToString(cfg["Redis:ip"]);
            pass = Convert.ToString(cfg["Redis:pass"]);
            Name = Convert.ToString(cfg["Redis:name"]);
            Instance = new CSRedis.ConnectionPool(ip, port, poolsize);
            Instance.Connected += (s, o) =>
            {
                CSRedis.RedisClient rc = s as CSRedis.RedisClient;
                if (!string.IsNullOrEmpty(pass)) rc.Auth(pass);
                if (database > 0) rc.Select(database);
            };
        }
    }
}

需要添加对Microsoft.Extensions.Configuration的引用。

在主项目下,引用该类库,打开Startup文件,把之前的构造函数换成如下所示:

        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();

            if (env.IsDevelopment())
            {
                // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
                builder.AddApplicationInsightsSettings(developerMode: true);
            }
            Configuration = builder.Build();
            RedisHelper.InitializeConfiguration(Configuration);          //Redis  
        }

同时之前的Configuration属性,也需要对应的修改,换成IConfigurationRoot类型,就可以了:

public IConfigurationRoot Configuration { get; }

以上。

在.Net Core 2.0中使用MySQL

在之前,我简单的介绍过在.net core中使用Mongodb(见文章《.Net Core系列教程(三)——使用Mongodb》),也使用过PostgreSQL(但是没有写文章介绍怎么使用,只是在文章《.Net Core系列教程(一)——环境搭建》中简单介绍过如何安装)。当然,我的文章质量都不高,只是把自己平时遇到的问题记录下来,很多问题是自己经历过之后在网上苦苦的寻找答案但都不适用或者不明了的情况下,自己摸索出来的解决方案,这也算是防止自己再次误入坑,也给遇到同样问题的朋友一点帮助吧。
下面说下怎样在.net core中使用MySQL,这个问题网上随便一搜有很多,我的当然也是从网上搜索来的,只是用自己的语言再次整理下而已。
在使用MySQL时,需要使用到MySQL的驱动,之前MySQL官方没有出驱动的时候,需要使用第三方的,不过现在有官方的驱动,还是尽量使用官方的吧,我这里也以官方的为准。另外还用到了Dapper这个小型ORM,这两个都可以通过Nuget来安装。需要注意的是,MySQL.Data需要安装最新版的(现在是6.10.3-rc版),旧版本不支持.net core 2.0
先在appsettings.json文件中,添加数据库的配置:

  "ConnectionStrings": {
    "MySqlConnection": "server=127.0.0.1;userid=root;pwd=root's password;port=3306;database=database's name;sslmode=none;Charset=utf8;"
  }

之后,增加数据库连接的Model类:

    public class ConnectionStrings
    {
        public string MySqlConnection { get; set; }        
    }

在Startup.cs文件中的ConfigureServices方法里,在services.AddMvc();之前增加添加调用:

services.Configure<Models.ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));

这样就会把appsettings.json中的数据库连接配置注入到Models.ConnectionStrings实体类中。
在控制器中,添加:
private readonly IOptions<Models.ConnectionStrings> _settings;
之后控制器的构造函数:

        public NewsController(IOptions<Models.ConnectionStrings> settings)
        {
            _settings = settings;
        }

这里我是直接把数据库连接的实体类传给了DAL层,这样写:

        public NewsController(IOptions<Models.ConnectionStrings> settings)
        {
            _settings = new BLL.ServiceImp.News(settings.Value);
        }

其中的settings.Value就是数据库连接实体类了

之后在DAL层中使用,同时也附带了几个数据库操作的实例:

        private string ConnString;
        public News(Models.ConnectionStrings Connection)
        {
            ConnString = Connection.MySqlConnection;
        }


        /// <summary>
        /// 取前top条新闻
        /// </summary>
        /// <returns></returns>
        public async Task<Models.ResultModel<List<Models.News>>> Newslatest(int top)
        {
            Models.ResultModel<List<Models.News>> result = new ResultModel<List<Models.News>>();

            using (var Conn = new MySqlConnection(ConnString))
            {
                string sql = "select Id,title,datetime,writer,remark,body,cid,status,isimage,thumb,category from news where status=1 order by datetime desc limit 0,@top";
                var data = await Conn.QueryAsync<Models.News>(sql, new { top = top });
                if(data.Count()>0)
                {
                    result.code = 0;
                    result.status = true;
                    result.message = "OK";
                    result.data = data.AsList();
                }
            }

            return result;
        }

        /// <summary>
        /// 取单条
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<Models.ResultModel<Models.News>> Detail(int id)
        {
            Models.ResultModel<Models.News> result = new ResultModel<Models.News>();
            using (var Conn =  new MySqlConnection(ConnString))
            {
                string sql = "select n.Id,title,datetime,writer,remark,body,cid,status,isimage,thumb,c.category from news n left join category c on n.cid=c.id where n.Id=@id";
                var res = await Conn.QueryAsync<Models.News>(sql, new { id = id });
                var data = res.SingleOrDefault();  //注意这里
                result.code = -404;
                result.message = "没有找到该条新闻";
                if (data != null)
                {
                    result.status = true;
                    result.message = "OK";
                    result.code = 0;
                    result.data = data;
                }
                else
                {
                    result.status = false;
                    result.code = -404;
                    result.message = "没有找到该条新闻";
                }
            }
            return result;
        }


        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<Models.ResultModel<object>> Delete(int id)
        {
            Models.ResultModel<object> result = new ResultModel<object>();
            using (var Conn = new MySqlConnection(ConnString))
            {
                string sql = "delete from news where Id=@id";
                var res = await Conn.ExecuteAsync(sql, new { id = id });
                result.status = res > 0;
                if (result.status)
                {
                    result.code = 0;
                    result.message = "success";
                }
            }

            return result;
        }


        /// <summary>
        /// 使用事务
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<Models.ResultModel<object>> DeleteCategory(int id)
        {
            Models.ResultModel<object> result = new ResultModel<object>();

            using (var Conn = new MySqlConnection(ConnString))
            {
                Conn.Open();  //注意这里,使用事务时,需要先open
                using (IDbTransaction transaction = Conn.BeginTransaction())
                {
                    try
                    {
                        string sql = "update news set cid=0 where cid=@id;delete from category where Id=@id;";   //删除分类,同时把该分类下的新闻移动到默认分类下
                        var res = await Conn.ExecuteAsync(sql, new { id = id });
                        transaction.Commit();   //提交事务
                        result.status = res > 0;
                        if (result.status)
                        {
                            result.code = 0;
                            result.message = "success";
                        }
                        else
                        {
                            transaction.Rollback(); //删除失败,回滚
                        }
                    }
                    catch
                    {
                        transaction.Rollback(); //出现异常,回滚
                    }
                }
                Conn.Close();   
                
            }
            return result;
        }

以上。

分类

最新文章

最近回复

归档

标签云

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

其它