标签 .net core 下的文章

.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,安装了之后果然好用。
希望这篇文章能帮到大家。

(完)

.Net Core 2.0的坑——POST提交HTTPS时证书报错的问题

最近接入腾讯云的短信平台,平台的接口是HTTPS的,开发环境是Windows,而生产环境是Linux(CentOS)。在开发调试的时候都正常通过,没问题;而部署到CentOS上之后,会报System.PlatformNotSupportedException: The handler does not support custom handling of certificates with this combination of libcurl (7.29.0) and its SSL backend ("NSS/3.34").错误。这个问题在网上找了一圈,好不容易Google到一个俄文的Blog,里面给出了一个解决方法,但是博主特别强调了一下,这是一个非常糟糕的方法:

yum update
yum install openssl-devel gcc
wget https://curl.haxx.se/download/<latest>.tar.gz
tar -zxf <latest>.tar.gz
cd <latest>
./configure --prefix=/usr/local/curl/ --without-nss --with-ssl=/usr/local/ssl/
make && make install 
 
echo '/usr/local/curl/lib' > /etc/ld.so.conf.d/libcurl.conf && ldconfig 

https://curl.haxx.se/download/<;latest>.tar.gz 是curl的最新版本下载地址,目前是
https://curl.haxx.se/download/curl-7.60.0.tar.gz
之后就可以正常提交了。
感谢原作者提供的方法,原博客:https://ales79.blogspot.com/2018/06/centos-7-libcurl-with-openssl-backend.html

我使用的Post方法如下:

        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认,否则打不开    
            return true;
        }

        /// <summary>
        /// Post提交数据
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="url">目标地址</param>
        /// <param name="contentType">数据类型</param>
        /// <param name="charset">编码</param>
        /// <returns></returns>
        public static string Post(string data, string url,string contentType,string charset= "utf-8")
        {
            System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接

            string result = "";//返回结果

            int timeout = 30;
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream reqStream = null;

            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;                
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);

                request.Method = "POST";
                request.Timeout = timeout * 1000;

                ////设置代理服务器
                //WebProxy proxy = new WebProxy();                          //定义一个网关对象
                //proxy.Address = new Uri(WxPayConfig.PROXY_URL);              //网关服务器端口:端口
                //request.Proxy = proxy;

                //设置POST的数据类型和长度
                request.ContentType = $"{contentType};charset={charset}";
                byte[] res = System.Text.Encoding.GetEncoding(charset).GetBytes(data);
                request.ContentLength = res.Length;

                //往服务器写入数据
                reqStream = request.GetRequestStream();
                reqStream.Write(res, 0, res.Length);
                reqStream.Close();

                //获取服务端返回
                response = (HttpWebResponse)request.GetResponse();

                //获取服务端返回数据
                StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.GetEncoding(charset));

                result = sr.ReadToEnd().Trim();
                sr.Close();
            }
            catch (System.Threading.ThreadAbortException e)
            {
                System.Threading.Thread.ResetAbort();
            }
            catch (WebException e)
            {
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    
                }
            }
            catch (Exception e)
            {
                
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

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
以上。

分类

最新文章

最近回复

  • 青山: 某种原因,暂停友链,抱歉。
  • 青山: 计划搬迁到腾讯云,正...
  • 老徐: 具体要哪个呢?
  • 老徐: 是不是有点老?
  • 青山: 哇,林志炫
  • 老白: 哇,这改的可以,能不...
  • 老徐: 23333
  • 许建华: 我是为了表情包来的~
  • vultr vps: 感谢分享深入学习
  • 青山: 每一次都是不同的感受

归档

标签云

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

其它