NET Framework项目移植到NET Core上遇到的一系列坑(2)
目录
- 获取请求的参数
- 获取完整的请求路径
- 获取域名
- 编码
- 文件上传的保存方法
- 获取物理路径
- 返回Json属性大小写问题
- webconfig的配置移植到appsettings.json
- 设置区域块MVC的路由器和访问区域块的视图
- NetCore访问静态资源文件
- MVC调用子页视图
- 过滤器
- 使用session和解决sessionID一直变化的问题
- MD5加密
- Path.Combine()
- DateTime
1.获取请求的参数
NET Framework版本:
1 Request["xxx"]; 2 Request.Files[0];
NET Core版本:
1 Request.Form["xxx"]; 2 Request.Form.Files[0];
2.获取完整的请求路径
NET Framework版本:
1 Request.RequestUri.ToString();
NET Core版本:
1 //先添加引用 2 3 using Microsoft.AspNetCore.Http.Extensions; 4 5 //再调用 6 Request.GetDisplayUrl();
3.获取域名
NET Framework版本:
1 HttpContext.Current.Request.Url.Authority
NET Core版本:
1 HttpContext.Request.Host.Value
4.编码
NET Framework版本:
1 System.Web.HttpContext.Current.Server.UrlEncode("<li class=\"test\"></li>") 2 "%3cli+class%3d%22test%22%3e%3c%2fli%3e" 3 System.Web.HttpContext.Current.Server.UrlDecode("%3cli+class%3d%22test%22%3e%3c%2fli%3e") 4 "<li class=\"test\"></li>"
NET Core版本:
1 //两种方法,建议用System.Web.HttpUtility 2 System.Web.HttpUtility.UrlEncode("<li class=\"test\"></li>"); 3 "%3cli+class%3d%22test%22%3e%3c%2fli%3e" 4 System.Web.HttpUtility.UrlDecode("%3cli+class%3d%22test%22%3e%3c%2fli%3e"); 5 "<li class=\"test\"></li>" 6 7 System.Net.WebUtility.UrlEncode("<li class=\"test\"></li>") 8 "%3Cli+class%3D%22test%22%3E%3C%2Fli%3E" 9 System.Net.WebUtility.UrlDecode("%3Cli+class%3D%22test%22%3E%3C%2Fli%3E") 10 "<li class=\"test\"></li>" 11 System.Net.WebUtility.UrlDecode("%3cli+class%3d%22test%22%3e%3c%2fli%3e") 12 "<li class=\"test\"></li>"
5.文件上传的保存方法
NET Framework版本:
1 var file = Request.Files[0]; 2 3 //blockFullPath指保存的物理路径 4 5 file.SaveAs(blockFullPath);
NET Core版本:
1 var file = Request.Form.Files[0]; 2 3 //blockFullPath指保存的物理路径 4 5 using (FileStream fs = new FileStream(blockFullPath, FileMode.CreateNew)) 6 7 { 8 9 file.CopyTo(fs); 10 11 fs.Flush(); 12 13 }
6.获取物理路径
NET Framework版本:
1 //作为一个全局变量获取物理路径的方法 2 3 public string ffmpegPathc = System.Web.Hosting.HostingEnvironment.MapPath("~/Content/ffmpeg/ffmpeg.exe"); 4 5 //获取在控制器的构造函数里直接调用Server.MapPath 6 7 ffmpegPathc = Server.MapPath("~/Content/ffmpeg/ffmpeg.exe");
NET Core版本:
1 //从ASP.NET Core RC2开始,可以通过注入 IHostingEnvironment 服务对象来取得Web根目录和内容根目录的物理路径。代码如下: 2 3 4 [Area("Admin")] 5 6 public class FileUploadController : Controller 7 8 { 9 10 private readonly IHostingEnvironment _hostingEnvironment; 11 12 13 14 public string ffmpegPathc = "";//System.Web.Hosting.HostingEnvironment.MapPath("~/Content/ffmpeg/ffmpeg.exe"); 15 16 17 18 public FileUploadController(IHostingEnvironment hostingEnvironment) 19 20 { 21 22 _hostingEnvironment = hostingEnvironment; 23 24 ffmpegPathc = _hostingEnvironment.WebRootPath + "/Content/ffmpeg/ffmpeg.exe"; 25 26 } 27 28 }
这样写每个控制器就都要写一个构造函数,很麻烦,所以可以把它抽离出来,写个公共类去调用。代码如下:
先自定义一个静态类:
1 using Microsoft.AspNetCore.Hosting; 2 3 using Microsoft.Extensions.DependencyInjection; 4 5 using System; 6 7 8 9 namespace GDSMPlateForm 10 11 { 12 13 public static class HttpHelper 14 15 { 16 17 public static IServiceProvider ServiceProvider { get; set; } 18 19 20 21 public static string GetServerPath(string path) 22 23 { 24 25 return ServiceProvider.GetRequiredService<IHostingEnvironment>().WebRootPath + path; 26 27 } 28 29 } 30 31 }
然后 在startup类下的Configure 方法下:
1 HttpHelper.ServiceProvider = app.ApplicationServices;
startup下的ConfigureServices放下注册方法(这一步必不可少,但是这里可以不写,因为IHostingEnvironment 是微软默认已经帮你注册了,如果是自己的服务,那么必须注册)。
1 services.AddSingleton<IHostingEnvironment, HostingEnvironment>();
最后获取物理路径就可以这样直接调用了:
1 public string ffmpegPathc = HttpHelper.GetServerPath("/Content/ffmpeg/ffmpeg.exe");
7.返回Json属性大小写问题
NET Core返回Json属性默认都会自动转为小写,但项目之前Json属性有些是大写的,所以需要配置成不转化为小写的形式。
Startup.cs的ConfigureServices方法下添加一行代码:
1 //Startup需要添加引用 2 3 using Newtonsoft.Json.Serialization; 4 5 //返回Json属性默认大小写 6 7 services.AddMvc().AddJsonOptions(o => { o.SerializerSettings.ContractResolver = new DefaultContractResolver(); });
8.webconfig的配置移植到appsettings.json
NET Framework版本:
直接可以读取webconfig配置文件:
string format = System.Configuration.ConfigurationManager.AppSettings["format"].ToString();
NET Core版本:
NET Core不再支持web.config,取而代之的是appsettings.json,所以需要把一些配置移植过去。
例如web.config下的一些配置
1 <appSettings> 2 3 <add key="ismdb" value="" /> 4 5 <add key="webpath" value="" /> 6 7 <add key="format" value="jpg,jpeg,png,gif,bmp,tif,svg/mp3,wav/mp4,avi,mpg,wmv,mkv,rmvb,mov,flv/zip/.ppt,.pptx" /> 8 9 <add key="imagesize" value="5242880" /> 10 11 <!--1024 * 1024 * 5 --> 12 13 <add key="musicsize" value="20971520" /> 14 15 <!--1024 * 1024 * 20 --> 16 17 <add key="mediasize" value="20971520" /> 18 19 <!--1024 * 1024 * 20 --> 20 21 <add key="packagesize" value="0" /> 22 23 <add key="pptsize" value="0" /> 24 25 </appSettings>
移植到appsettings.json
1 { 2 3 "Logging": { 4 5 "IncludeScopes": false, 6 7 "LogLevel": { 8 9 "Default": "Warning" 10 11 } 12 13 }, 14 15 "webpath": "", 16 17 "format": "jpg,jpeg,png,gif,bmp,tif,svg/mp3,wav/mp4,avi,mpg,wmv,mkv,rmvb,mov,flv/zip/.ppt,.pptx", 18 19 "imagesize": "5242880", 20 21 "musicsize": "20971520", 22 23 "mediasize": "20971520", 24 25 "packagesize": "0", 26 27 "pptsize": "0" 28 29 }
然后编写一个类去调用这个appsettings.json
1 using Microsoft.Extensions.Configuration; 2 3 using System.IO; 4 5 6 7 namespace GDSMPlateForm 8 9 { 10 11 public class RConfigureManage 12 13 { 14 15 public static string GetConfigure(string key) 16 17 { 18 19 20 21 //添加 json 文件路径 22 23 var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json"); 24 25 //创建配置根对象 26 27 var configurationRoot = builder.Build(); 28 29 30 31 //取配置根下的 name 部分 32 33 string secvalue = configurationRoot.GetSection(key).Value; 34 35 return secvalue; 36 37 } 38 39 } 40 41 }
调用的方式:
1 string format = RConfigureManage.GetConfigure("format");
9.设置区域块MVC的路由器和访问区域块的视图
NET Framework版本:
NET Framework新建一个区域会自带一个类设置路由器的,如图:
1 using System.Web.Mvc; 2 3 4 5 namespace GDSMPlateForm.Areas.Admin 6 7 { 8 9 public class AdminAreaRegistration : AreaRegistration 10 11 { 12 13 public override string AreaName 14 15 { 16 17 get 18 19 { 20 21 return "Admin"; 22 23 } 24 25 } 26 27 28 29 public override void RegisterArea(AreaRegistrationContext context) 30 31 { 32 33 context.MapRoute( 34 35 "Admin_default", 36 37 "Admin/{controller}/{action}/{id}", 38 39 new { action = "Index", id = UrlParameter.Optional } 40 41 ); 42 43 } 44 45 } 46 47 }
NET Core版本:
NET Core新建一个区域不会自带一个类用于设置路由器,所以需要在Startup类的Configure方法里多加一条路由器设置
1 app.UseMvc(routes => 2 3 { 4 5 routes.MapRoute( 6 7 name: "areas", 8 9 template: "{area:exists}/{controller=Home}/{action=Index}/{id?}" 10 11 ); 12 13 });
然后需要在每个控制器下添加一个标签,指定该控制器属于哪个区域的,如图:
不加的话访问不到区域的视图,报404错误。
10.NetCore访问静态资源文件
NET Framework版本:
NET Framework可以在webconfig下配置这些静态资源文件
1 <staticContent> 2 3 <mimeMap fileExtension="." mimeType="image/svg+xml" /> 4 5 <mimeMap fileExtension=".properties" mimeType="application/octet-stream" /> 6 7 </staticContent>
NET Core版本:
NET Core并没有webconfig,所以需要在Startup类的Configure方法里自己配置。
NET Core项目默认的资源文件存在wwwroot下,可以通过app.UseStaticFiles方法自己定义资源文件的路径还有类型。
1 ar provider = new FileExtensionContentTypeProvider(); 2 3 provider.Mappings[".properties"] = "application/octet-stream"; 4 5 app.UseStaticFiles(new StaticFileOptions 6 7 { 8 9 FileProvider = new PhysicalFileProvider( 10 11 Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Content")), 12 13 RequestPath = "/Content", 14 15 ContentTypeProvider = provider 16 17 });
11.MVC调用子页视图
NET Framework版本:
1 @Html.Action("UserBackView", "UserManage")
NET Core版本:
NET Core不再支持Html.Action(),不过可以手动自己去实现它。
自定义一个静态类 HtmlHelperViewExtensions,命名空间设置为 Microsoft.AspNetCore.Mvc.Rendering。网上找的一个类,复制过来就行了,如下:
1 using Microsoft.AspNetCore.Html; 2 3 using Microsoft.AspNetCore.Http; 4 5 using Microsoft.AspNetCore.Mvc.Infrastructure; 6 7 using Microsoft.AspNetCore.Routing; 8 9 using Microsoft.Extensions.DependencyInjection; 10 11 using System; 12 13 using System.IO; 14 15 using System.Threading.Tasks; 16 17 18 19 namespace Microsoft.AspNetCore.Mvc.Rendering 20 21 { 22 23 public static class HtmlHelperViewExtensions 24 25 { 26 27 public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null) 28 29 { 30 31 var controller = (string)helper.ViewContext.RouteData.Values["controller"]; 32 33 34 35 return Action(helper, action, controller, parameters); 36 37 } 38 39 40 41 public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null) 42 43 { 44 45 var area = (string)helper.ViewContext.RouteData.Values["area"]; 46 47 48 49 return Action(helper, action, controller, area, parameters); 50 51 } 52 53 54 55 public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null) 56 57 { 58 59 if (action == null) 60 61 throw new ArgumentNullException("action"); 62 63 64 65 if (controller == null) 66 67 throw new ArgumentNullException("controller"); 68 69 70 71 72 73 var task = RenderActionAsync(helper, action, controller, area, parameters); 74 75 76 77 return task.Result; 78 79 } 80 81 82 83 private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null) 84 85 { 86 87 // fetching required services for invocation 88 89 var serviceProvider = helper.ViewContext.HttpContext.RequestServices; 90 91 var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>(); 92 93 var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>(); 94 95 var actionSelector = serviceProvider.GetRequiredService<IActionSelector>(); 96 97 98 99 // creating new action invocation context 100 101 var routeData = new RouteData(); 102 103 foreach (var router in helper.ViewContext.RouteData.Routers) 104 105 { 106 107 routeData.PushState(router, null, null); 108 109 } 110 111 routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null); 112 113 routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null); 114 115 116 117 //get the actiondescriptor 118 119 RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData }; 120 121 var candidates = actionSelector.SelectCandidates(routeContext); 122 123 var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates); 124 125 126 127 var originalActionContext = actionContextAccessor.ActionContext; 128 129 var originalhttpContext = httpContextAccessor.HttpContext; 130 131 try 132 133 { 134 135 var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features); 136 137 if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper))) 138 139 { 140 141 newHttpContext.Items.Remove(typeof(IUrlHelper)); 142 143 } 144 145 newHttpContext.Response.Body = new MemoryStream(); 146 147 var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor); 148 149 actionContextAccessor.ActionContext = actionContext; 150 151 var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext); 152 153 await invoker.InvokeAsync(); 154 155 newHttpContext.Response.Body.Position = 0; 156 157 using (var reader = new StreamReader(newHttpContext.Response.Body)) 158 159 { 160 161 return new HtmlString(reader.ReadToEnd()); 162 163 } 164 165 } 166 167 catch (Exception ex) 168 169 { 170 171 return new HtmlString(ex.Message); 172 173 } 174 175 finally 176 177 { 178 179 actionContextAccessor.ActionContext = originalActionContext; 180 181 httpContextAccessor.HttpContext = originalhttpContext; 182 183 if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper))) 184 185 { 186 187 helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper)); 188 189 } 190 191 } 192 193 } 194 } }
然后在Startup中的 ConfigureServices 方法添加:
1 services.AddSingleton<IHttpContextAccessor, HttpContextAccessor(); 2 3 services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
这样就可以像NET Framework版本一样去调用子页面视图了:
1 @Html.Action("UserBackView", "UserManage")
12.过滤器
NET Framework版本
NET Framework版本上Global.asax中Application_Start方法可以做很多配置,过滤器也是其中一种。
-
1 protected void Application_Start() 2 3 { 4 5 AreaRegistration.RegisterAllAreas(); 6 7 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//全局过滤器集合 8 9 RouteConfig.RegisterRoutes(RouteTable.Routes); 10 11 BundleConfig.RegisterBundles(BundleTable.Bundles); 12 13 } 14 15 16 17 public class FilterConfig 18 19 { 20 21 public static void RegisterGlobalFilters(GlobalFilterCollection filters) 22 23 { 24 25 filters.Add(new HandleErrorAttribute()); 26 27 filters.Add(new LoginCheckFilterAttribute() { IsCheck = true });//自定义一个过滤器 28 29 } 30 31 } 32 33 34 35 //继承过滤器基类并重写方法 36 37 public class LoginCheckFilterAttribute : ActionFilterAttribute 38 39 { 40 41 //表示是否检查 42 43 public bool IsCheck { get; set; } 44 45 //Action方法执行之前执行此方法 46 47 public override void OnActionExecuting(ActionExecutingContext filterContext) 48 49 { 50 51 base.OnActionExecuting(filterContext); 52 53 if (IsCheck) 54 55 { 56 57 //添加自己的逻辑 58 59 } 60 61 } 62 63 }
NET Core版本:
NET Core不在支持Global.asax,很多配置写在Startup里。过滤器的添加方法如下:
1 public void ConfigureServices(IServiceCollection services) 2 3 { 4 5 services.AddMvc(options => 6 7 { 8 9 options.Filters.Add(typeof(AuthorizationFilters));// 自定义一个类AuthorizationFilters,添加身份验证过滤器 10 11 }); 12 13 } 14 15 16 17 /// <summary> 18 19 /// 身份认证类继承IAuthorizationFilter接口 20 21 /// </summary> 22 23 public class AuthorizationFilters :IAuthorizationFilter 24 25 { 26 27 /// <summary> 28 29 /// 请求验证,当前验证部分不要抛出异常,ExceptionFilter不会处理 30 31 /// </summary> 32 33 /// <param name="context">请求内容信息</param> 34 35 public void OnAuthorization(AuthorizationFilterContext context) 36 37 { 38 39 //写自己的逻辑 40 41 } 42 43 }
13.使用session和解决sessionID一直变化的问题
NET Core版本:
在Startup类里添加session配置
1 public void ConfigureServices(IServiceCollection services) 2 3 { 4 5 services.AddDistributedMemoryCache(); 6 7 services.AddSession(option => 8 9 { //设置session过期时间 10 11 option.IOTimeout = TimeSpan.FromHours(1); 12 13 option.IdleTimeout = TimeSpan.FromHours(1); 14 15 }); 16 17 services.AddMvc(); 18 19 } 20 21 22 23 public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider svp) 24 25 { 26 27 app.UseSession();//必须在app.UseMvc之前,否则报错 28 29 app.UseMvc(routes => 30 31 { 32 33 routes.MapRoute( 34 35 name: "default", 36 37 template: "{controller=Home}/{action=Index}/{id?}"); 38 39 }); 40 41 }
配置完成后session就可以使用了,不过当Session保存有值,id才不会改变,没有值每次刷新都会变,可以给在使用session时可以给session随便赋个值以保证sessionid不会一直变化。
1 HttpContext.Session.Set("login", Encoding.UTF8.GetBytes("login")); 2 3 string sessionid = HttpContext.Session.Id;
14.MD5加密
NET Framework版本:
1 2 //参数str类型是string 3 4 System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5");
NET Core版本:用以下这个方法替换了
1 /// <summary> 2 3 /// 32位MD5加密 4 5 /// </summary> 6 7 /// <param name="input"></param> 8 9 /// <returns></returns> 10 11 private static string Md5Hash(string input) 12 13 { 14 15 MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider(); 16 17 byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input)); 18 19 StringBuilder sBuilder = new StringBuilder(); 20 21 for (int i = 0; i < data.Length; i++) 22 23 { 24 25 sBuilder.Append(data[i].ToString("x2")); 26 27 } 28 29 return sBuilder.ToString(); 30 31 }
15.Path.Combine()
该方法是路径拼接,在NET Framework版本和NET Core版本同样支持,不过用Path.Combine拼接出来的路径是这样的:xxxx\\xxxx,用的是“\\”,这种路径在Window系统上可以正常运行,但是在Linux上是无法定位到准确的路径的。Linux上的路径是这样的:xxxx/xxxx。所以当我们用Path.Combine这个方法时最好再配合一个替换方法:
Path.Combine(path1,path2).Replace("\\","/");
16.DateTime
1 // 方法在不同平台返回的时间格式不一样,即使使用ToString("yyyy/MM/dd")希望转成'2019/04/18'这种格式,但在Centos7平台下它还是变成了‘2019-04-18’这样,可以考虑用Replace方法去替换。 2 core 2.1 DateTime.Now.ToString()
原文地址:https://www.cnblogs.com/lonelyxmas/p/12001657.html