NET Framework项目移植到NET Core上遇到的一系列坑
原文:NET Framework项目移植到NET Core上遇到的一系列坑
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
目录
8.webconfig的配置移植到appsettings.json
13.使用session和解决sessionID一直变化的问题
1.获取请求的参数
NET Framework版本:
-
Request["xxx"];
-
Request.Files[0];
NET Core版本:
-
Request.Form["xxx"];
-
Request.Form.Files[0];
2.获取完整的请求路径
NET Framework版本:
Request.RequestUri.ToString();
NET Core版本:
-
//先添加引用
-
using Microsoft.AspNetCore.Http.Extensions;
-
//再调用
-
Request.GetDisplayUrl();
3.获取域名
NET Framework版本:
HttpContext.Current.Request.Url.Authority
NET Core版本:
HttpContext.Request.Host.Value
4.编码
NET Framework版本:
-
System.Web.HttpContext.Current.Server.UrlEncode("<li class=\"test\"></li>")
-
"%3cli+class%3d%22test%22%3e%3c%2fli%3e"
-
System.Web.HttpContext.Current.Server.UrlDecode("%3cli+class%3d%22test%22%3e%3c%2fli%3e")
-
"<li class=\"test\"></li>"
NET Core版本:
-
//两种方法,建议用System.Web.HttpUtility
-
System.Web.HttpUtility.UrlEncode("<li class=\"test\"></li>");
-
"%3cli+class%3d%22test%22%3e%3c%2fli%3e"
-
System.Web.HttpUtility.UrlDecode("%3cli+class%3d%22test%22%3e%3c%2fli%3e");
-
"<li class=\"test\"></li>"
-
-
System.Net.WebUtility.UrlEncode("<li class=\"test\"></li>")
-
"%3Cli+class%3D%22test%22%3E%3C%2Fli%3E"
-
System.Net.WebUtility.UrlDecode("%3Cli+class%3D%22test%22%3E%3C%2Fli%3E")
-
"<li class=\"test\"></li>"
-
System.Net.WebUtility.UrlDecode("%3cli+class%3d%22test%22%3e%3c%2fli%3e")
-
"<li class=\"test\"></li>"
-


5.文件上传的保存方法
NET Framework版本:
-
var file = Request.Files[0];
-
//blockFullPath指保存的物理路径
-
file.SaveAs(blockFullPath);
NET Core版本:
-
var file = Request.Form.Files[0];
-
//blockFullPath指保存的物理路径
-
using (FileStream fs = new FileStream(blockFullPath, FileMode.CreateNew))
-
{
-
file.CopyTo(fs);
-
fs.Flush();
-
}
6.获取物理路径
NET Framework版本:
-
//作为一个全局变量获取物理路径的方法
-
public string ffmpegPathc = System.Web.Hosting.HostingEnvironment.MapPath("~/Content/ffmpeg/ffmpeg.exe");
-
//获取在控制器的构造函数里直接调用Server.MapPath
-
ffmpegPathc = Server.MapPath("~/Content/ffmpeg/ffmpeg.exe");
NET Core版本:
从ASP.NET Core RC2开始,可以通过注入 IHostingEnvironment 服务对象来取得Web根目录和内容根目录的物理路径。代码如下:
-
[Area("Admin")]
-
public class FileUploadController : Controller
-
{
-
private readonly IHostingEnvironment _hostingEnvironment;
-
-
public string ffmpegPathc = "";//System.Web.Hosting.HostingEnvironment.MapPath("~/Content/ffmpeg/ffmpeg.exe");
-
-
public FileUploadController(IHostingEnvironment hostingEnvironment)
-
{
-
_hostingEnvironment = hostingEnvironment;
-
ffmpegPathc = _hostingEnvironment.WebRootPath + "/Content/ffmpeg/ffmpeg.exe";
-
}
-
}
这样写每个控制器就都要写一个构造函数,很麻烦,所以可以把它抽离出来,写个公共类去调用。代码如下:
先自定义一个静态类:
-
using Microsoft.AspNetCore.Hosting;
-
using Microsoft.Extensions.DependencyInjection;
-
using System;
-
-
namespace GDSMPlateForm
-
{
-
public static class HttpHelper
-
{
-
public static IServiceProvider ServiceProvider { get; set; }
-
-
public static string GetServerPath(string path)
-
{
-
return ServiceProvider.GetRequiredService<IHostingEnvironment>().WebRootPath + path;
-
}
-
}
-
}
然后 在startup类下的Configure 方法下:
HttpHelper.ServiceProvider = app.ApplicationServices;
startup下的ConfigureServices放下注册方法(这一步必不可少,但是这里可以不写,因为IHostingEnvironment 是微软默认已经帮你注册了,如果是自己的服务,那么必须注册)。
services.AddSingleton<IHostingEnvironment, HostingEnvironment>();
最后获取物理路径就可以这样直接调用了:
public string ffmpegPathc = HttpHelper.GetServerPath("/Content/ffmpeg/ffmpeg.exe");
7.返回Json属性大小写问题
NET Core返回Json属性默认都会自动转为小写,但项目之前Json属性有些是大写的,所以需要配置成不转化为小写的形式。
Startup.cs的ConfigureServices方法下添加一行代码:
-
//Startup需要添加引用
-
using Newtonsoft.Json.Serialization;
-
//返回Json属性默认大小写
-
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下的一些配置
-
<appSettings>
-
<add key="ismdb" value="" />
-
<add key="webpath" value="" />
-
<add key="format" value="jpg,jpeg,png,gif,bmp,tif,svg/mp3,wav/mp4,avi,mpg,wmv,mkv,rmvb,mov,flv/zip/.ppt,.pptx" />
-
<add key="imagesize" value="5242880" />
-
<!--1024 * 1024 * 5 -->
-
<add key="musicsize" value="20971520" />
-
<!--1024 * 1024 * 20 -->
-
<add key="mediasize" value="20971520" />
-
<!--1024 * 1024 * 20 -->
-
<add key="packagesize" value="0" />
-
<add key="pptsize" value="0" />
-
</appSettings>
移植到appsettings.json
-
{
-
"Logging": {
-
"IncludeScopes": false,
-
"LogLevel": {
-
"Default": "Warning"
-
}
-
},
-
"webpath": "",
-
"format": "jpg,jpeg,png,gif,bmp,tif,svg/mp3,wav/mp4,avi,mpg,wmv,mkv,rmvb,mov,flv/zip/.ppt,.pptx",
-
"imagesize": "5242880",
-
"musicsize": "20971520",
-
"mediasize": "20971520",
-
"packagesize": "0",
-
"pptsize": "0"
-
}
然后编写一个类去调用这个appsettings.json
-
using Microsoft.Extensions.Configuration;
-
using System.IO;
-
-
namespace GDSMPlateForm
-
{
-
public class RConfigureManage
-
{
-
public static string GetConfigure(string key)
-
{
-
-
//添加 json 文件路径
-
var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
-
//创建配置根对象
-
var configurationRoot = builder.Build();
-
-
//取配置根下的 name 部分
-
string secvalue = configurationRoot.GetSection(key).Value;
-
return secvalue;
-
}
-
}
-
}
调用的方式:
string format = RConfigureManage.GetConfigure("format");
9.设置区域块MVC的路由器和访问区域块的视图
NET Framework版本:
NET Framework新建一个区域会自带一个类设置路由器的,如图:

-
using System.Web.Mvc;
-
-
namespace GDSMPlateForm.Areas.Admin
-
{
-
public class AdminAreaRegistration : AreaRegistration
-
{
-
public override string AreaName
-
{
-
get
-
{
-
return "Admin";
-
}
-
}
-
-
public override void RegisterArea(AreaRegistrationContext context)
-
{
-
context.MapRoute(
-
"Admin_default",
-
"Admin/{controller}/{action}/{id}",
-
new { action = "Index", id = UrlParameter.Optional }
-
);
-
}
-
}
-
}
NET Core版本:
NET Core新建一个区域不会自带一个类用于设置路由器,所以需要在Startup类的Configure方法里多加一条路由器设置
-
app.UseMvc(routes =>
-
{
-
routes.MapRoute(
-
name: "areas",
-
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
-
);
-
});
然后需要在每个控制器下添加一个标签,指定该控制器属于哪个区域的,如图:

不加的话访问不到区域的视图,报404错误。
10.NetCore访问静态资源文件
NET Framework版本:
NET Framework可以在webconfig下配置这些静态资源文件
-
<staticContent>
-
<mimeMap fileExtension="." mimeType="image/svg+xml" />
-
<mimeMap fileExtension=".properties" mimeType="application/octet-stream" />
-
</staticContent>
NET Core版本:
NET Core并没有webconfig,所以需要在Startup类的Configure方法里自己配置。
NET Core项目默认的资源文件存在wwwroot下,可以通过app.UseStaticFiles方法自己定义资源文件的路径还有类型。
-
var provider = new FileExtensionContentTypeProvider();
-
provider.Mappings[".properties"] = "application/octet-stream";
-
app.UseStaticFiles(new StaticFileOptions
-
{
-
FileProvider = new PhysicalFileProvider(
-
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Content")),
-
RequestPath = "/Content",
-
ContentTypeProvider = provider
-
});
11.MVC调用子页视图
NET Framework版本:
@Html.Action("UserBackView", "UserManage")
NET Core版本:
NET Core不再支持Html.Action(),不过可以手动自己去实现它。
自定义一个静态类 HtmlHelperViewExtensions,命名空间设置为 Microsoft.AspNetCore.Mvc.Rendering。网上找的一个类,复制过来就行了,如下:
-
using Microsoft.AspNetCore.Html;
-
using Microsoft.AspNetCore.Http;
-
using Microsoft.AspNetCore.Mvc.Infrastructure;
-
using Microsoft.AspNetCore.Routing;
-
using Microsoft.Extensions.DependencyInjection;
-
using System;
-
using System.IO;
-
using System.Threading.Tasks;
-
-
namespace Microsoft.AspNetCore.Mvc.Rendering
-
{
-
public static class HtmlHelperViewExtensions
-
{
-
public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
-
{
-
var controller = (string)helper.ViewContext.RouteData.Values["controller"];
-
-
return Action(helper, action, controller, parameters);
-
}
-
-
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
-
{
-
var area = (string)helper.ViewContext.RouteData.Values["area"];
-
-
return Action(helper, action, controller, area, parameters);
-
}
-
-
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
-
{
-
if (action == null)
-
throw new ArgumentNullException("action");
-
-
if (controller == null)
-
throw new ArgumentNullException("controller");
-
-
-
var task = RenderActionAsync(helper, action, controller, area, parameters);
-
-
return task.Result;
-
}
-
-
private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
-
{
-
// fetching required services for invocation
-
var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
-
var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
-
var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
-
var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();
-
-
// creating new action invocation context
-
var routeData = new RouteData();
-
foreach (var router in helper.ViewContext.RouteData.Routers)
-
{
-
routeData.PushState(router, null, null);
-
}
-
routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);
-
routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);
-
-
//get the actiondescriptor
-
RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
-
var candidates = actionSelector.SelectCandidates(routeContext);
-
var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);
-
-
var originalActionContext = actionContextAccessor.ActionContext;
-
var originalhttpContext = httpContextAccessor.HttpContext;
-
try
-
{
-
var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features);
-
if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))
-
{
-
newHttpContext.Items.Remove(typeof(IUrlHelper));
-
}
-
newHttpContext.Response.Body = new MemoryStream();
-
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
-
actionContextAccessor.ActionContext = actionContext;
-
var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext);
-
await invoker.InvokeAsync();
-
newHttpContext.Response.Body.Position = 0;
-
using (var reader = new StreamReader(newHttpContext.Response.Body))
-
{
-
return new HtmlString(reader.ReadToEnd());
-
}
-
}
-
catch (Exception ex)
-
{
-
return new HtmlString(ex.Message);
-
}
-
finally
-
{
-
actionContextAccessor.ActionContext = originalActionContext;
-
httpContextAccessor.HttpContext = originalhttpContext;
-
if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))
-
{
-
helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));
-
}
-
}
-
}
-
}
-
}
然后在Startup中的 ConfigureServices 方法添加:
-
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor();
-
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
这样就可以像NET Framework版本一样去调用子页面视图了:
@Html.Action("UserBackView", "UserManage")
12.过滤器
NET Framework版本
NET Framework版本上Global.asax中Application_Start方法可以做很多配置,过滤器也是其中一种。
-
protected void Application_Start()
-
{
-
AreaRegistration.RegisterAllAreas();
-
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//全局过滤器集合
-
RouteConfig.RegisterRoutes(RouteTable.Routes);
-
BundleConfig.RegisterBundles(BundleTable.Bundles);
-
}
-
-
public class FilterConfig
-
{
-
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
-
{
-
filters.Add(new HandleErrorAttribute());
-
filters.Add(new LoginCheckFilterAttribute() { IsCheck = true });//自定义一个过滤器
-
}
-
}
-
-
//继承过滤器基类并重写方法
-
public class LoginCheckFilterAttribute : ActionFilterAttribute
-
{
-
//表示是否检查
-
public bool IsCheck { get; set; }
-
//Action方法执行之前执行此方法
-
public override void OnActionExecuting(ActionExecutingContext filterContext)
-
{
-
base.OnActionExecuting(filterContext);
-
if (IsCheck)
-
{
-
//添加自己的逻辑
-
}
-
}
-
}
NET Core版本:
NET Core不在支持Global.asax,很多配置写在Startup里。过滤器的添加方法如下:
-
public void ConfigureServices(IServiceCollection services)
-
{
-
services.AddMvc(options =>
-
{
-
options.Filters.Add(typeof(AuthorizationFilters));// 自定义一个类AuthorizationFilters,添加身份验证过滤器
-
});
-
}
-
-
/// <summary>
-
/// 身份认证类继承IAuthorizationFilter接口
-
/// </summary>
-
public class AuthorizationFilters :IAuthorizationFilter
-
{
-
/// <summary>
-
/// 请求验证,当前验证部分不要抛出异常,ExceptionFilter不会处理
-
/// </summary>
-
/// <param name="context">请求内容信息</param>
-
public void OnAuthorization(AuthorizationFilterContext context)
-
{
-
//写自己的逻辑
-
}
-
}
13.使用session和解决sessionID一直变化的问题
NET Core版本:
在Startup类里添加session配置
-
public void ConfigureServices(IServiceCollection services)
-
{
-
services.AddDistributedMemoryCache();
-
services.AddSession(option =>
-
{ //设置session过期时间
-
option.IOTimeout = TimeSpan.FromHours(1);
-
option.IdleTimeout = TimeSpan.FromHours(1);
-
});
-
services.AddMvc();
-
}
-
-
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider svp)
-
{
-
app.UseSession();//必须在app.UseMvc之前,否则报错
-
app.UseMvc(routes =>
-
{
-
routes.MapRoute(
-
name: "default",
-
template: "{controller=Home}/{action=Index}/{id?}");
-
});
-
}
配置完成后session就可以使用了,不过当Session保存有值,id才不会改变,没有值每次刷新都会变,可以给在使用session时可以给session随便赋个值以保证sessionid不会一直变化。
-
HttpContext.Session.Set("login", Encoding.UTF8.GetBytes("login"));
-
string sessionid = HttpContext.Session.Id;
14.MD5加密
NET Framework版本:
-
//参数str类型是string
-
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5");
NET Core版本:用以下这个方法替换了
-
/// <summary>
-
/// 32位MD5加密
-
/// </summary>
-
/// <param name="input"></param>
-
/// <returns></returns>
-
private static string Md5Hash(string input)
-
{
-
MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
-
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
-
StringBuilder sBuilder = new StringBuilder();
-
for (int i = 0; i < data.Length; i++)
-
{
-
sBuilder.Append(data[i].ToString("x2"));
-
}
-
return sBuilder.ToString();
-
}
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上遇到的一系列坑的更多相关文章
- NET Framework项目移植到NET Core上遇到的一系列坑(2)
目录 获取请求的参数 获取完整的请求路径 获取域名 编码 文件上传的保存方法 获取物理路径 返回Json属性大小写问题 webconfig的配置移植到appsettings.json 设置区域块MVC ...
- NET Framework项目移植到NET Core上踩的坑(1)
本文章向大家介绍NET Framework项目移植到NET Core上遇到的一系列坑,主要包括NET Framework项目移植到NET Core上遇到的一系列坑使用实例.应用技巧.基本知识点总结和需 ...
- 在Visual Studio中将现有.NET Framework项目迁移至.NET Core 1.1 Preview 1
1)下载安装包含 .NET Core 1.1 Preview 1 的 SDK:Windows x64 安装包(下载地址列表) 2)下载最新 VS 2015 NuGet 插件:https://dist. ...
- 如何移植.NET Framework项目至.NET Core?
公司的项目一直采用.NET框架来开发Web项目.目前基础类库均为.NET Framework 4.6.2版本.Caching, Logging,DependencyInjection,Configur ...
- 开源纯C#工控网关+组态软件(十)移植到.NET Core
一. 引子 写这个开源系列已经十来篇了.自从十年前注册博客园以来,关注了张善友.老赵.xiaotie.深蓝色右手等一众大牛,也围观了逗比的吉日嘎啦.精密顽石等形形色色的园友.然而整整十年一篇文章都 ...
- 通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core? .Net Web开发技术栈
通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core? 什么是.NET?什么是.NET Framework?本文将从上往下,循序渐进的介绍一系列相关.NET的概念 ...
- .NET项目迁移到.NET Core操作指南
为什么要从.NET迁移到.NET Core? .NET Core提供的特性 .NET Core性能提升 .NET如何迁移到.NET Core? 迁移工作量评估(API兼容性分析) 迁移方案制定 通过类 ...
- (转)项目迁移_.NET项目迁移到.NET Core操作指南
原文地址:https://www.cnblogs.com/heyuquan/p/dotnet-migration-to-dotnetcore.html 这篇文章,汇集了大量优秀作者写的关于" ...
- .Net Core上用于代替System.Drawing的类库
目前.Net Core上没有System.Drawing这个类库,想要在.Net Core上处理图片得另辟蹊径. 微软给出了将来取代System.Drawing的方案,偏向于使用一个单独的服务端进行各 ...
随机推荐
- 相关性不一定等于因果性:从 Yule-Simpson’s Paradox 讲起
1. 两件事伴随发生,不代表他们之间有因果关系 - 从一些荒诞相关性案例说起 在日常生活和数据分析中,我们可以得到大量相关性的结论,例如: 输入X变量,有98%置信度得到Y变量 只要努力,就能成功 只 ...
- php踩过的那些坑(1) isset()详解
前言:在日常开发中经常会遇到使用isset()函数检测一个变量是否设置,有什么需要注意的地方,今天一起来讨论一下 注:测试的php版本是5.6.22 一.前方有坑 先上代码: $arr['a'] = ...
- 如何彻底理解Java抽象类 为什么要用抽象类 什么情况下用抽象类
如何彻底理解Java抽象类 为什么要用抽象类 什么情况下用抽象类 呐,到底什么是抽象类,有时明明一个普通类就可以解决了,为啥非得整个抽象类,装逼吗 我曾带着这样的疑惑,查了很多资料,看了很多源码,写了 ...
- 目不识丁的我使用Python编写汉字注音小工具
一万点暴击伤害 人懒起来太可怕了,放了个十一充分激发了我的惰性.然后公众号就这么停了半个月,好惭愧- 新学期儿子的幼儿园上线了APP,每天作业通过app布置后,家长需要陪着孩子学习,并上传视频才算完成 ...
- 华为云ModelArts2.0来袭
[摘要] modelarts自发布以来,不断地更新增加新的功能来为AI工程师们带来新的服务,在这次的全联接大会上EI服务产品部总经理贾永利宣布--华为云AI重装升级,并重磅发布一站式AI开发管理平台M ...
- Android手机打造你的Python&Java开发工具!
开发者桌面 之前写过一篇文章:将Android手机打造成你的python开发者桌面 在安卓手机上通过Termux软件,创建一个模拟Linux系统,它的好处就是无需root,即可在手机中编写Python ...
- iOS 自定义TabBarController
转自:http://blog.csdn.net/xn4545945/article/details/35994863 一.自定义的思路 iOS中的TabBarController确实已经很强大了,大部 ...
- Redux和Context对比
Redux和Context对比 如果项目体量较小,只是需要一个公共的store存储state,而不讲究使用action来管理state,那context完全可以胜任.反之,则是redux的优点. co ...
- go基础之基本数据结构(数组、slice、map)
go基本的数据结构有数组.slice.map,高级数据结构为结构体为用户自定义类型.本片文章主要讲解三大基本数据结构. 数组 slice Map 数组 数组是包含单个类型的元素序列,但是长度固定的数据 ...
- RabbitMQ的三大交换器
pom文件都是相同的 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=" ...