NET Framework项目移植到NET Core上遇到的一系列坑

原文: NET Framework项目移植到NET Core上遇到的一系列坑

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zt102545/article/details/87968865

目录

1.获取请求的参数

2.获取完整的请求路径

3.获取域名

4.编码

5.文件上传的保存方法

6.获取物理路径

7.返回Json属性大小写问题

8.webconfig的配置移植到appsettings.json

9.设置区域块MVC的路由器和访问区域块的视图

10.NetCore访问静态资源文件

11.MVC调用子页视图

12.过滤器

13.使用session和解决sessionID一直变化的问题

14.MD5加密

15.Path.Combine()

16.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版本:

Request.RequestUri.ToString();
   
   
   
   

NET Core版本:


    
    
    
    
  1. //先添加引用
  2. using Microsoft.AspNetCore.Http.Extensions;
  3. //再调用
  4. Request.GetDisplayUrl();

3.获取域名

NET Framework版本:

HttpContext.Current.Request.Url.Authority
   
   
   
   

NET Core版本:

HttpContext.Request.Host.Value
   
   
   
   

4.编码

NET Framework版本:


    
    
    
    
  1. System.Web.HttpContext.Current.Server.UrlEncode( "
  2. ")
  • "%3cli+class%3d%22test%22%3e%3c%2fli%3e"
  • System.Web.HttpContext.Current.Server.UrlDecode( "%3cli+class%3d%22test%22%3e%3c%2fli%3e")
  • "
  • "

    NET Core版本:

    
        
        
        
        
    1. //两种方法,建议用System.Web.HttpUtility
    2. System.Web.HttpUtility.UrlEncode( "
    3. ");
  • "%3cli+class%3d%22test%22%3e%3c%2fli%3e"
  • System.Web.HttpUtility.UrlDecode( "%3cli+class%3d%22test%22%3e%3c%2fli%3e");
  • "
  • "
  • System.Net.WebUtility.UrlEncode( "
  • ")
  • "%3Cli+class%3D%22test%22%3E%3C%2Fli%3E"
  • System.Net.WebUtility.UrlDecode( "%3Cli+class%3D%22test%22%3E%3C%2Fli%3E")
  • "
  • "
  • System.Net.WebUtility.UrlDecode( "%3cli+class%3d%22test%22%3e%3c%2fli%3e")
  • "
  • "
  • NET Framework项目移植到NET Core上遇到的一系列坑_第1张图片

    NET Framework项目移植到NET Core上遇到的一系列坑_第2张图片

     

    5.文件上传的保存方法

    NET Framework版本:

    
        
        
        
        
    1. var file = Request.Files[ 0];
    2. //blockFullPath指保存的物理路径
    3. file.SaveAs(blockFullPath);

    NET Core版本:

    
        
        
        
        
    1. var file = Request.Form.Files[ 0];
    2. //blockFullPath指保存的物理路径
    3. using (FileStream fs = new FileStream(blockFullPath, FileMode.CreateNew))
    4. {
    5. file.CopyTo(fs);
    6. fs.Flush();
    7. }

    6.获取物理路径

    NET Framework版本:

    
        
        
        
        
    1. //作为一个全局变量获取物理路径的方法
    2. public string ffmpegPathc = System.Web.Hosting.HostingEnvironment.MapPath( "~/Content/ffmpeg/ffmpeg.exe");
    3. //获取在控制器的构造函数里直接调用Server.MapPath
    4. ffmpegPathc = Server.MapPath( "~/Content/ffmpeg/ffmpeg.exe");

    NET Core版本:

    从ASP.NET Core RC2开始,可以通过注入 IHostingEnvironment 服务对象来取得Web根目录和内容根目录的物理路径。代码如下:

    
        
        
        
        
    1. [ Area("Admin")]
    2. public class FileUploadController : Controller
    3. {
    4. private readonly IHostingEnvironment _hostingEnvironment;
    5. public string ffmpegPathc = ""; //System.Web.Hosting.HostingEnvironment.MapPath("~/Content/ffmpeg/ffmpeg.exe");
    6. public FileUploadController(IHostingEnvironment hostingEnvironment)
    7. {
    8. _hostingEnvironment = hostingEnvironment;
    9. ffmpegPathc = _hostingEnvironment.WebRootPath + "/Content/ffmpeg/ffmpeg.exe";
    10. }
    11. }

    这样写每个控制器就都要写一个构造函数,很麻烦,所以可以把它抽离出来,写个公共类去调用。代码如下:

    先自定义一个静态类:

    
        
        
        
        
    1. using Microsoft.AspNetCore.Hosting;
    2. using Microsoft.Extensions.DependencyInjection;
    3. using System;
    4. namespace GDSMPlateForm
    5. {
    6. public static class HttpHelper
    7. {
    8. public static IServiceProvider ServiceProvider { get; set; }
    9. public static string GetServerPath(string path)
    10. {
    11. return ServiceProvider.GetRequiredService().WebRootPath + path;
    12. }
    13. }
    14. }

    然后 在startup类下的Configure 方法下:

    HttpHelper.ServiceProvider = app.ApplicationServices;
       
       
       
       

    startup下的ConfigureServices放下注册方法(这一步必不可少,但是这里可以不写,因为IHostingEnvironment 是微软默认已经帮你注册了,如果是自己的服务,那么必须注册)。

    services.AddSingleton();
       
       
       
       

    最后获取物理路径就可以这样直接调用了:

    public string ffmpegPathc = HttpHelper.GetServerPath("/Content/ffmpeg/ffmpeg.exe");
       
       
       
       

    7.返回Json属性大小写问题

    NET Core返回Json属性默认都会自动转为小写,但项目之前Json属性有些是大写的,所以需要配置成不转化为小写的形式。

    Startup.cs的ConfigureServices方法下添加一行代码:

    
        
        
        
        
    1. //Startup需要添加引用
    2. using Newtonsoft.Json.Serialization;
    3. //返回Json属性默认大小写
    4. 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. <add key="ismdb" value="" />
    3. <add key="webpath" value="" />
    4. <add key="format" value="jpg,jpeg,png,gif,bmp,tif,svg/mp3,wav/mp4,avi,mpg,wmv,mkv,rmvb,mov,flv/zip/.ppt,.pptx" />
    5. <add key="imagesize" value="5242880" />
    6. <add key="musicsize" value="20971520" />
    7. <add key="mediasize" value="20971520" />
    8. <add key="packagesize" value="0" />
    9. <add key="pptsize" value="0" />
    10. appSettings>

    移植到appsettings.json

    
        
        
        
        
    1. {
    2. "Logging": {
    3. "IncludeScopes": false,
    4. "LogLevel": {
    5. "Default": "Warning"
    6. }
    7. },
    8. "webpath": "",
    9. "format": "jpg,jpeg,png,gif,bmp,tif,svg/mp3,wav/mp4,avi,mpg,wmv,mkv,rmvb,mov,flv/zip/.ppt,.pptx",
    10. "imagesize": "5242880",
    11. "musicsize": "20971520",
    12. "mediasize": "20971520",
    13. "packagesize": "0",
    14. "pptsize": "0"
    15. }

    然后编写一个类去调用这个appsettings.json

    
        
        
        
        
    1. using Microsoft.Extensions.Configuration;
    2. using System.IO;
    3. namespace GDSMPlateForm
    4. {
    5. public class RConfigureManage
    6. {
    7. public static string GetConfigure(string key)
    8. {
    9. //添加 json 文件路径
    10. var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile( "appsettings.json");
    11. //创建配置根对象
    12. var configurationRoot = builder.Build();
    13. //取配置根下的 name 部分
    14. string secvalue = configurationRoot.GetSection(key).Value;
    15. return secvalue;
    16. }
    17. }
    18. }

    调用的方式:

    string format = RConfigureManage.GetConfigure("format");
       
       
       
       

    9.设置区域块MVC的路由器和访问区域块的视图

    NET Framework版本:

    NET Framework新建一个区域会自带一个类设置路由器的,如图:

    NET Framework项目移植到NET Core上遇到的一系列坑_第3张图片

    
        
        
        
        
    1. using System.Web.Mvc;
    2. namespace GDSMPlateForm.Areas.Admin
    3. {
    4. public class AdminAreaRegistration : AreaRegistration
    5. {
    6. public override string AreaName
    7. {
    8. get
    9. {
    10. return "Admin";
    11. }
    12. }
    13. public override void RegisterArea(AreaRegistrationContext context)
    14. {
    15. context.MapRoute(
    16. "Admin_default",
    17. "Admin/{controller}/{action}/{id}",
    18. new { action = "Index", id = UrlParameter.Optional }
    19. );
    20. }
    21. }
    22. }

    NET Core版本:

    NET Core新建一个区域不会自带一个类用于设置路由器,所以需要在Startup类的Configure方法里多加一条路由器设置

    
        
        
        
        
    1. app.UseMvc(routes =>
    2. {
    3. routes.MapRoute(
    4. name: "areas",
    5. template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
    6. );
    7. });

    然后需要在每个控制器下添加一个标签,指定该控制器属于哪个区域的,如图:

    NET Framework项目移植到NET Core上遇到的一系列坑_第4张图片

    不加的话访问不到区域的视图,报404错误。

    10.NetCore访问静态资源文件

    NET Framework版本:

    NET Framework可以在webconfig下配置这些静态资源文件

    
        
        
        
        
    1. <staticContent>
    2. <mimeMap fileExtension="." mimeType="image/svg+xml" />
    3. <mimeMap fileExtension=".properties" mimeType="application/octet-stream" />
    4. staticContent>

    NET Core版本:

    NET Core并没有webconfig,所以需要在Startup类的Configure方法里自己配置。

    NET Core项目默认的资源文件存在wwwroot下,可以通过app.UseStaticFiles方法自己定义资源文件的路径还有类型。

    
        
        
        
        
    1. var provider = new FileExtensionContentTypeProvider();
    2. provider.Mappings[ ".properties"] = "application/octet-stream";
    3. app.UseStaticFiles( new StaticFileOptions
    4. {
    5. FileProvider = new PhysicalFileProvider(
    6. Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Content")),
    7. RequestPath = "/Content",
    8. ContentTypeProvider = provider
    9. });

    11.MVC调用子页视图

    NET Framework版本:

    @Html.Action("UserBackView", "UserManage")
       
       
       
       

    NET Core版本:

    NET Core不再支持Html.Action(),不过可以手动自己去实现它。

    自定义一个静态类 HtmlHelperViewExtensions,命名空间设置为  Microsoft.AspNetCore.Mvc.Rendering。网上找的一个类,复制过来就行了,如下:

    
        
        
        
        
    1. using Microsoft.AspNetCore.Html;
    2. using Microsoft.AspNetCore.Http;
    3. using Microsoft.AspNetCore.Mvc.Infrastructure;
    4. using Microsoft.AspNetCore.Routing;
    5. using Microsoft.Extensions.DependencyInjection;
    6. using System;
    7. using System.IO;
    8. using System.Threading.Tasks;
    9. namespace Microsoft.AspNetCore.Mvc.Rendering
    10. {
    11. public static class HtmlHelperViewExtensions
    12. {
    13. public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
    14. {
    15. var controller = ( string)helper.ViewContext.RouteData.Values[ "controller"];
    16. return Action(helper, action, controller, parameters);
    17. }
    18. public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
    19. {
    20. var area = ( string)helper.ViewContext.RouteData.Values[ "area"];
    21. return Action(helper, action, controller, area, parameters);
    22. }
    23. public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
    24. {
    25. if (action == null)
    26. throw new ArgumentNullException( "action");
    27. if (controller == null)
    28. throw new ArgumentNullException( "controller");
    29. var task = RenderActionAsync(helper, action, controller, area, parameters);
    30. return task.Result;
    31. }
    32. private static async Task RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
    33. {
    34. // fetching required services for invocation
    35. var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
    36. var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService();
    37. var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService();
    38. var actionSelector = serviceProvider.GetRequiredService();
    39. // creating new action invocation context
    40. var routeData = new RouteData();
    41. foreach ( var router in helper.ViewContext.RouteData.Routers)
    42. {
    43. routeData.PushState(router, null, null);
    44. }
    45. routeData.PushState( null, new RouteValueDictionary( new { controller = controller, action = action, area = area }), null);
    46. routeData.PushState( null, new RouteValueDictionary(parameters ?? new { }), null);
    47. //get the actiondescriptor
    48. RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
    49. var candidates = actionSelector.SelectCandidates(routeContext);
    50. var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);
    51. var originalActionContext = actionContextAccessor.ActionContext;
    52. var originalhttpContext = httpContextAccessor.HttpContext;
    53. try
    54. {
    55. var newHttpContext = serviceProvider.GetRequiredService().Create(helper.ViewContext.HttpContext.Features);
    56. if (newHttpContext.Items.ContainsKey( typeof(IUrlHelper)))
    57. {
    58. newHttpContext.Items.Remove( typeof(IUrlHelper));
    59. }
    60. newHttpContext.Response.Body = new MemoryStream();
    61. var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
    62. actionContextAccessor.ActionContext = actionContext;
    63. var invoker = serviceProvider.GetRequiredService().CreateInvoker(actionContext);
    64. await invoker.InvokeAsync();
    65. newHttpContext.Response.Body.Position = 0;
    66. using ( var reader = new StreamReader(newHttpContext.Response.Body))
    67. {
    68. return new HtmlString(reader.ReadToEnd());
    69. }
    70. }
    71. catch (Exception ex)
    72. {
    73. return new HtmlString(ex.Message);
    74. }
    75. finally
    76. {
    77. actionContextAccessor.ActionContext = originalActionContext;
    78. httpContextAccessor.HttpContext = originalhttpContext;
    79. if (helper.ViewContext.HttpContext.Items.ContainsKey( typeof(IUrlHelper)))
    80. {
    81. helper.ViewContext.HttpContext.Items.Remove( typeof(IUrlHelper));
    82. }
    83. }
    84. }
    85. }
    86. }

    然后在Startup中的 ConfigureServices 方法添加:

    
        
        
        
        
    1. services.AddSingleton
    2. services.AddSingleton();

    这样就可以像NET Framework版本一样去调用子页面视图了:

    @Html.Action("UserBackView", "UserManage")
       
       
       
       

    12.过滤器

    NET Framework版本

    NET Framework版本上Global.asax中Application_Start方法可以做很多配置,过滤器也是其中一种。

    
        
        
        
        
    1. protected void Application_Start()
    2. {
    3. AreaRegistration.RegisterAllAreas();
    4. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); //全局过滤器集合
    5. RouteConfig.RegisterRoutes(RouteTable.Routes);
    6. BundleConfig.RegisterBundles(BundleTable.Bundles);
    7. }
    8. public class FilterConfig
    9. {
    10. public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    11. {
    12. filters.Add( new HandleErrorAttribute());
    13. filters.Add( new LoginCheckFilterAttribute() { IsCheck = true }); //自定义一个过滤器
    14. }
    15. }
    16. //继承过滤器基类并重写方法
    17. public class LoginCheckFilterAttribute : ActionFilterAttribute
    18. {
    19. //表示是否检查
    20. public bool IsCheck { get; set; }
    21. //Action方法执行之前执行此方法
    22. public override void OnActionExecuting(ActionExecutingContext filterContext)
    23. {
    24. base.OnActionExecuting(filterContext);
    25. if (IsCheck)
    26. {
    27. //添加自己的逻辑
    28. }
    29. }
    30. }

    NET Core版本:

    NET Core不在支持Global.asax,很多配置写在Startup里。过滤器的添加方法如下:

    
        
        
        
        
    1. public void ConfigureServices(IServiceCollection services)
    2. {
    3. services.AddMvc(options =>
    4. {
    5. options.Filters.Add( typeof(AuthorizationFilters)); // 自定义一个类AuthorizationFilters,添加身份验证过滤器
    6. });
    7. }
    8. ///
    9. /// 身份认证类继承IAuthorizationFilter接口
    10. ///
    11. public class AuthorizationFilters : IAuthorizationFilter
    12. {
    13. ///
    14. /// 请求验证,当前验证部分不要抛出异常,ExceptionFilter不会处理
    15. ///
    16. /// 请求内容信息
    17. public void OnAuthorization(AuthorizationFilterContext context)
    18. {
    19. //写自己的逻辑
    20. }
    21. }

    13.使用session和解决sessionID一直变化的问题

    NET Core版本:

    在Startup类里添加session配置

    
        
        
        
        
    1. public void ConfigureServices(IServiceCollection services)
    2. {
    3. services.AddDistributedMemoryCache();
    4. services.AddSession(option =>
    5. { //设置session过期时间
    6. option.IOTimeout = TimeSpan.FromHours( 1);
    7. option.IdleTimeout = TimeSpan.FromHours( 1);
    8. });
    9. services.AddMvc();
    10. }
    11. public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider svp)
    12. {
    13. app.UseSession(); //必须在app.UseMvc之前,否则报错
    14. app.UseMvc(routes =>
    15. {
    16. routes.MapRoute(
    17. name: "default",
    18. template: "{controller=Home}/{action=Index}/{id?}");
    19. });
    20. }

    配置完成后session就可以使用了,不过当Session保存有值,id才不会改变,没有值每次刷新都会变,可以给在使用session时可以给session随便赋个值以保证sessionid不会一直变化。

    
        
        
        
        
    1. HttpContext.Session.Set( "login", Encoding.UTF8.GetBytes( "login"));
    2. string sessionid = HttpContext.Session.Id;

    14.MD5加密

    NET Framework版本:

    
        
        
        
        
    1. //参数str类型是string
    2. System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5");

    NET Core版本:用以下这个方法替换了

    
        
        
        
        
    1. ///
    2. /// 32位MD5加密
    3. ///
    4. ///
    5. ///
    6. private static string Md5Hash(string input)
    7. {
    8. MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
    9. byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
    10. StringBuilder sBuilder = new StringBuilder();
    11. for ( int i = 0; i < data.Length; i++)
    12. {
    13. sBuilder.Append(data[i].ToString( "x2"));
    14. }
    15. return sBuilder.ToString();
    16. }

    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

    donet core 2.1 DateTime.Now.ToString() 方法在不同平台返回的时间格式不一样,即使使用ToString("yyyy/MM/dd")希望转成'2019/04/18'这种格式,但在Centos7平台下它还是变成了‘2019-04-18’这样,可以考虑用Replace方法去替换。

    你可能感兴趣的:(NET Framework项目移植到NET Core上遇到的一系列坑)