第二节:必备中间件集成1(Cookie、Session、HttpClient、静态资源、路由配置、跨域等)

一. Cookie、Session、HttpClient

1. 说明

 在Asp.Net Core Mvc中,服务的注册通常是在ConfigureService中进行,一个框架会注册很多服务,每个服务都会对应一系列配置,所以我们这里采用【扩展方法】的模式,将需要注册的服务剥离到 YpfCore.Utils层中,从而使ConfigureService中更加简洁。

(1). 扩展方法相关:https://www.cnblogs.com/yaopengfei/p/6921057.html

(2). Cookie和Session相关:https://www.cnblogs.com/yaopengfei/p/11270816.html

(3). HttpClient相关:https://www.cnblogs.com/yaopengfei/p/11300888.html

2. Cookie和Session

 Session存储可以基于内存,可以基于Redis、SQLServer,下面重点封装基于内存和Redis的存储,需要安装程序集:【Microsoft.Extensions.Caching.StackExchangeRedis】,在YpfCore.Utils层中CoreMvcExtensions类中进行扩展。

(1). 相应配置 

策略封装代码分享

  /// <summary>
        /// Cookie和Session策略
        /// (基于redis的Session策略注释,如果开启,需要把CacheStrategyExtensions中的AddMemoryCache注释掉)
        /// </summary>
        /// <param name="services"></param>
        ///  <param name="CacheType">Session载体,Memory基于内存存储,StackRedis基于Redis存储,null什么也不注册</param>
        /// <returns></returns>
        public static IServiceCollection AddCookieAndSession(this IServiceCollection services, string CacheType)
        {
            //1.Cookie策略
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => false;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            //2. Session相关配置
            //2.1 配置Session相关的载体
            switch (CacheType)
            {
                case "Memory": {
                        services.AddDistributedMemoryCache();
                    }; break;
                case "StackRedis":
                    {
                        //需要把其它封装中的AddMemoryCache 或 AddDistributedMemoryCache都注释掉
                        services.AddStackExchangeRedisCache(options =>
                        {
                            options.Configuration = ConfigHelp.GetString("RedisStr");
                            //options.InstanceName = "SampleInstance";   //给key加个前缀
                        });
                    }; break;
                case "null":
                    {
                        //什么也不注册
                    }; break;
                default: throw new Exception("Session载体无效");
            }
View Code

配置文件

"RedisStr": "119.xx.xx.xx:6379,password=123456,defaultDatabase=0"

ConfigureService集成

  //添加Cookie和Session配置
  services.AddCookieAndSession("StackRedis");

Configure中开启 

 //2. 启用Cookie策略
  app.UseCookiePolicy();
 //3. 启用Session
 app.UseSession();

测试代码

 {
                var user = new T_SysUser()
                {
                    id = Guid.NewGuid().ToString("N"),
                    userAccount = "1234"
                };
                HttpContext.Session.Set<T_SysUser>("userInfor", user);
                var data1 = HttpContext.Session.Get<T_SysUser>("userInfor");
}

(2). Session扩展

 原Session的方法单调,这里提供两种扩展方法,分别是基于【Newtonsoft.Json】和 【protobuf-net】,详见YpfCore.Utils层中的SessionExtensions类。

代码分享:

/// <summary>
    /// Session的两种扩展方式
    /// 依赖程序集:【Microsoft.AspNetCore.Http】和【Microsoft.AspNetCore.Http.Extensions】
    /// 两种序列化模式:【Newtonsoft.Json】和 【protobuf-net】
    /// 其中 【protobuf-net】序列化的类名上要加 [ProtoContract],属性上要加 [ProtoMember(1)] [ProtoMember(2)]
    /// </summary>
    public static class SessionExtensions
    {
        #region 01-利用Newtonsoft.Json进行扩展
        public static void Set<T>(this ISession session, string key, T value)
        {
            session.SetString(key, JsonConvert.SerializeObject(value));
        }

        public static T Get<T>(this ISession session, string key)
        {
            var value = session.GetString(key);
            return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
        }
        #endregion

        #region 02-利用protobuf-net进行扩展
        public static void Set2<T>(this ISession session, string key, T value)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                Serializer.Serialize(stream, value);
                byte[] byteArrary = stream.ToArray();
                session.Set(key, byteArrary);
            }
        }

        public static T Get2<T>(this ISession session, string key)
        {
            byte[] byteArray = session.Get(key);
            if (byteArray == null)
            {
                return default(T);
            }
            else
            {
                using (MemoryStream stream = new MemoryStream(byteArray))
                {
                    return Serializer.Deserialize<T>(stream);
                }
            }
        }
        #endregion
    }
View Code

调用测试:

            {
                var user = new T_SysUser()
                {
                    id = Guid.NewGuid().ToString("N"),
                    userAccount = "1234"
                };
                HttpContext.Session.Set<T_SysUser>("userInfor", user);
                var data1 = HttpContext.Session.Get<T_SysUser>("userInfor");
            }

3. HttpClient

(1) .方式一

 常规写法,在ConfigureService注入AddHttpClient对象,这里同样是以扩展方法的形式剥离的YpfCore.Utils层中,然后在控制器中注入IHttpClientFactory 对象即可。

代码分享

ConfigureService中注入:services.AddMyHttpClient();

封装代码:

public static class CoreMvcExtensions
    {
        /// <summary>
        /// 注册HttpClient服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddMyHttpClient(this IServiceCollection services)
        {
            //1.基本用法
            services.AddHttpClient();
            //2. 命名客户端(用于指定表头和请求根目录---目前用不到)
            services.AddHttpClient("client1", c =>
            {
                c.BaseAddress = new Uri("http://localhost:15319/");
                c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
                c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
            });

            return services;
        }

    }
View Code

(2). 方式二

 彻底封装,在YpfCore.Utils层中的RequestHelp类中模拟注入的方式封装Get和Post方法,Core Mvc中直接调用即可,不需要ConfigureService中注册任何东西。

封装代码:

// <summary>
    /// 基于HttpClientFactory的请求封装
    /// 依赖【Microsoft.Extensions.DependencyInjection】和 【Microsoft.Extensions.Http】
    /// 可以直接调用,在CoreMvc中不再需要注入AddHttpClient了,因为下面封装里已Add进去了
    /// </summary>
    public class RequestHelp
    {
        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <returns></returns>
        public static string MyGetRequest(string url)
        {
            var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
            IHttpClientFactory clientFactory = serviceProvider.GetService<IHttpClientFactory>();
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var client = clientFactory.CreateClient();
            var response = client.SendAsync(request).Result;
            var myResult = response.Content.ReadAsStringAsync().Result;
            return myResult;
        }

        /// <summary>
        /// Post请求-表单形式
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="content">请求内容</param>
        /// <returns></returns>
        public static string MyPostRequest(string url, string content)
        {
            var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
            IHttpClientFactory clientFactory = serviceProvider.GetService<IHttpClientFactory>();
            var request = new HttpRequestMessage(HttpMethod.Post, url);
            //内容的处理
            request.Content = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded");
            var client = clientFactory.CreateClient();
            var response = client.SendAsync(request).Result;
            var myResult = response.Content.ReadAsStringAsync().Result;
            return myResult;
        }

        /// <summary>
        /// Post请求-Json形式
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="content">请求内容</param>
        /// <returns></returns>
        public static string MyPostRequestJson(string url, object content)
        {
            var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
            IHttpClientFactory clientFactory = serviceProvider.GetService<IHttpClientFactory>();
            var request = new HttpRequestMessage(HttpMethod.Post, url);
            //内容的处理
            request.Content = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");
            var client = clientFactory.CreateClient();
            var response = client.SendAsync(request).Result;
            var myResult = response.Content.ReadAsStringAsync().Result;
            return myResult;
        }

    }
View Code

调用测试:

            {
                string url1 = "http://localhost:29793/api/DemoApi/GetMsg1?userAccount=admin&userId=123456";
                string url2 = "http://localhost:29793/api/DemoApi/GetMsg2";
                string url3 = "http://localhost:29793/api/DemoApi/GetMsg3";
                //Get请求
                var result1 = RequestHelp.MyGetRequest(url1);
                //Post-表单提交
                var result2 = RequestHelp.MyPostRequest(url2, "userAccount=admin&userId=123456");
                //Post-Json提交
                var user = new
                {
                    userId = "admin",
                    userAccount = "123456"
                };
                var result3 = RequestHelp.MyPostRequestJson(url3, user);
            }

 

二. 静态资源、路由、跨域

 参考

 (1). 静态资源参考:https://www.cnblogs.com/yaopengfei/p/10823322.html

 (2). 路由参考:https://www.cnblogs.com/yaopengfei/p/11849496.html

 (3). 跨域参考:https://www.cnblogs.com/yaopengfei/p/11191938.html

1. 静态资源

  Asp.Net Core MVC中默认开启静态文件中间件(在Configure方法中 app.UseStaticFiles()),即wwwroot目录(即根目录)下的文件均可以访问,通常我们可能需要单独在根目录下新建文件,比如DownLoad,那么就需要自行配置。

代码分享: 

            //1. 启用静态资源
            app.UseStaticFiles();
            //开启DownLoad文件夹,便于下载相关的请求的进行访问(发布的时候,发布目录中必须要有下面的文件夹!!!)
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "DownLoad")),
                //配置相对路径(建议和前面的名起个一样的,当然也可以起别的,注意前面要有/)
                RequestPath = "/DownLoad"
            }); 

2. 路由

 这里我们配置两个路由规则,普通路由和Area区域路由,    区域中的action必须配置: [Area("区域名")],  对于WebApi,可以单独配置:[Route("api/xxx_areas/[controller]/[action]")]和[ApiController] ,同样可以替换Restful默认风格。

 代码分享:

           app.UseEndpoints(endpoints =>
            {
                //默认路由
                endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Admin}/{action=LoginIndex}/{id?}");
               //pattern: "{controller=Demo}/{action=Test1}/{id?}");

                //区域路由(要放在默认路由的后面)
                //注:必须以特性的形式在对应控制器上加上区域名称 [Area("XXXX")]
                endpoints.MapControllerRoute(
                       name: "default2",
                       pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
            });

3. 跨域

  这里直接在Configure中全局配置允许跨域请求,至于单独作用,见之前的参考文档。

 app.UseCors(options =>
 {
      options.AllowAnyOrigin()
                 .AllowAnyMethod()
                 .AllowAnyHeader();
 });

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
原文地址:https://www.cnblogs.com/yaopengfei/p/14236551.html