.net core 基础知识
1.IOC(转:https://www.cnblogs.com/artech/p/inside-asp-net-core.html)
IoC的全名Inverse of Control,翻译成中文就是“控制反转”或者“控制倒置”。控制反转也好,控制倒置也罢,它体现的意思是控制权的转移,即原来控制权在A手中,现在需要B来接管。那么具体对于软件设计来说,IoC所谓的控制权的转移具有怎样的体现呢?要回答这个问题,就需要先了解IoC的C(Control)究竟指的是怎样一种控制。对于我们所在的任何一件事,不论其大小,其实可以分解成相应的步骤,所以任何一件事都有其固有的流程,IoC涉及的所谓控制可以理解为“针对流程的控制
我们通过一个具体事例来说明传统的设计在采用了IoC之后针对流程的控制是如何实现反转的。比如说现在设计一个针对Web的MVC类库,我们不妨将其命名为MvcLib。简单起见,这个类库中只包含如下这个同名的静态类
public static class MvcLib { public static Task ListenAsync(Uri address); public static Task<Request> ReceiveAsync(); public static Task<Controller> CreateControllerAsync(Request request); public static Task<View> ExecuteControllerAsync(Controller controller); public static Task RenderViewAsync(View view); }
MvcLib提供了如上5个方法帮助我们完成整个HTTP请求流程中的5个核心任务。具体来说,ListenAsync方法启动一个监听器并将其绑定到指定的地址进行HTTP请求的监听,抵达的请求通过ReceiveAsync方法进行接收,我们将接收到的请求通过一个Request对象来表示。CreateControllerAsync方法根据接收到的请求解析并激活请求的目标Controller对象。ExecuteControllerAsync方法执行激活的Controller并返回一个表示视图的View对象。RenderViewAsync最终将View对象转换成HTML并作为当前请求响应的内容返回给请求的客户端。
现在我们在这个MvcLib的基础上创建一个真正的MVC应用,那么除了按照MvcLib的规范自定义具体的Controller和View之外,我们还需要自行控制从请求的监听与接收、Controller的激活与执行以及View的最终呈现在内的整个流程,这样一个执行流程反映在如下所示的代码中。
class Program { static async Task Main() { while (true) { Uri address = new Uri("http://0.0.0.0:8080/mvcapp"); await MvcLib.ListenAsync(address); while (true) { var request = await MvcLib.ReceiveAsync(); var controller = await MvcLib.CreateControllerAsync(request); var view = await MvcLib.ExecuteControllerAsync(controller); await MvcLib.RenderViewAsync(view); } } } }
2.好莱坞法则
在好莱坞,把简历递交给演艺公司后就只有回家等待。由演艺公司对整个娱乐项目的完全控制,演员只能被动式的接受电影公司的工作,在需要的环节中,完成自己的演出。“不要给我们打电话,我们会给你打电话(don‘t call us, we‘ll call you)”这是著名的好莱坞法则( Hollywood Principle或者 Hollywood Low),IoC完美地体现了这一法则。
在IoC的应用语境中,框架就像是掌握整个电影制片流程的电影公司,由于它是整个工作流程的实际控制者,所以只有它知道哪个环节需要哪些组件。应用程序就像是演员,它只需要按照框架定制的规则注册这些组件就可以了,因为框架会在适当的时机字典加载并执行注册的组件。
以熟悉的ASP.NET Core MVC或者ASP.NET MVC应用开发来说,我们只需要按照约定规则(比如目录结构和命名等)定义相应的Controller类型和View文件就可以了。当ASP.NET (Core )MVC框架在进行处理请求的过程中,它会根据解析生成的路由参数定义为对应的Controller类型,并按照预定义的规则找到我们定义的Controller,然后自动创建并执行它。如果定义在当前Action方法需要呈现一个View,框架自身会根据预定义的目录约定找到我们定义的View文件,并对它实施动态编译和执行。整个流程处处体现了“框架Call应用”的好莱坞法则。
总的来说,我们在一个框架的基础上进行应用开发,就相当于在一条调试好的流水线上生成某种商品,我们只需要在相应的环节准备对应的原材料,最终下线的就是我们希望得到的最终产品。IoC几乎是所有框架均具有的一个固有属性,从这个意义上讲,“IoC框架”的说法其实是错误的,世界上并没有什么IoC框架,或者说几乎所有的框架都是IoC框架。
3.依赖注入(DI容器)
IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架中以实现对流程的复用,并按照“好莱坞法则”实现应用程序的代码与框架之间的交互。我们可以采用若干设计模式以不同的方式实现IoC
DI是一种“对象提供型”的设计模式,在这里我们将提供的对象统称为“服务”、“服务对象”或者“服务实例”。在一个采用DI的应用中,在定义某个服务类型的时候,我们直接将依赖的服务采用相应的方式注入进来。按照“面向接口编程”的原则,被注入的最好是依赖服务的接口而非实现。
在应用启动的时候,我们会对所需的服务进行全局注册。服务一般都是针对接口进行注册的,服务注册信息的核心目的是为了在后续消费过程中能够根据接口创建或者提供对应的服务实例。按照“好莱坞法则”,应用只需要定义好所需的服务,服务实例的激活和调用则完全交给框架来完成,而框架则会采用一个独立的“容器(Container)”来提供所需的每一个服务实例。
我们将这个被框架用来提供服务的容器称为“DI容器”,也由很多人将其称为“IoC容器”,根据我们在《控制反转》针对IoC的介绍,我不认为后者是一个合理的称谓。DI容器之所以能够按照我们希望的方式来提供所需的服务是因为该容器是根据服务注册信息来创建的,服务注册了包含提供所需服务实例的所有信息。
以Autofac框架为列
框架特性
1,灵活的组件实例化:Autofac支持自动装配,给定的组件类型Autofac自动选择使用构造函数注入或者属性注入,Autofac还可以基于lambda表达式创建实例,这使得容器非常灵活,很容易和其他的组件集成。
2,资源管理的可视性:基于依赖注入容器构建的应用程序的动态性,意味着什么时候应该处理那些资源有点困难。Autofac通过容器来跟踪组件的资源管理。对于不需要清理的对象,例如Console.Out,我们调用ExternallyOwned()方法告诉容器不用清理。细粒度的组件生命周期管理:应用程序中通常可以存在一个应用程序范围的容器实例,在应用程序中还存在大量的一个请求的范围的对象,例如一个HTTP请求,一个IIS工作者线程或者用户的会话结束时结束。通过嵌套的容器实例和对象的作用域使得资源的可视化。
3,Autofac的设计上非常务实,这方面更多是为我们这些容器的使用者考虑:
●组件侵入性为零:组件不需要去引用Autofac。
●灵活的模块化系统:通过模块化组织你的程序,应用程序不用纠缠于复杂的XML配置系统或者是配置参数。
●自动装配:可以是用lambda表达式注册你的组件,autofac会根据需要选择构造函数或者属性注入
●XML配置文件的支持:XML配置文件过度使用时很丑陋,但是在发布的时候通常非常有用
(1).属性注入
builder.Register(c => new A { B = c.Resolve<B>() });
为了支持循环依赖,使用激活的事件处理程序:
builder.Register(c => new A()).OnActivated(e => e.Instance.B = e.Context.Resolve<B>());
如果是一个反射组件,使用PropertiesAutowired()修改注册属性:
builder.RegisterType<A>().PropertiesAutowired();
如果你有一个特定的属性和值需要连接,你可以使用WithProperty()修改:
builder.RegisterType<A>().WithProperty("PropertyName", propertyValue);
(2).方法注入
调用一个方法来设置一个组件的值的最简单的方法是,使用一个lambda表达式组件和正确的调用激活处理方法。
builder.Register(c => { var result = new MyObjectType(); var dep = c.Resolve<TheDependency>(); result.SetTheDependency(dep); return result; });
如果你不能使用一个lambda表达式注册,你可以添加一个激活事件处理程序(activating event handler)
builder .Register<MyObjectType>() .OnActivating(e => { var dep = e.Context.Resolve<TheDependency>(); e.Instance.SetTheDependency(dep); });
(3).构造函数注入
// 创建你的builder var builder = new ContainerBuilder(); // 通常你只关心这个接口的一个实现 builder.RegisterType<SomeType>().As<IService>(); // 当然,如果你想要全部的服务(不常用),可以这么写: builder.RegisterType<SomeType>().AsSelf().As<IService>();
生命周期
AutoFac中的生命周期概念非常重要,AutoFac也提供了强大的生命周期管理的能力。
AutoFac定义了三种生命周期:
Per Dependency
Single Instance
Per Lifetime Scope
Per Dependency为默认的生命周期,也被称为’transient’或’factory’,其实就是每次请求都创建一个新的对象
[Fact] public void per_dependency() { var builder = new ContainerBuilder(); builder.RegisterType<MyClass>().InstancePerDependency(); IContainer container = builder.Build(); var myClass1 = container.Resolve<MyClass>(); var myClass2 = container.Resolve<MyClass>(); Assert.NotEqual(myClass1,myClass2); }
Single Instance也很好理解,就是每次都用同一个对象
[Fact] public void single_instance() { var builder = new ContainerBuilder(); builder.RegisterType<MyClass>().SingleInstance(); IContainer container = builder.Build(); var myClass1 = container.Resolve<MyClass>(); var myClass2 = container.Resolve<MyClass>(); Assert.Equal(myClass1,myClass2); }
Per Lifetime Scope,同一个Lifetime生成的对象是同一个实例
[Fact] public void per_lifetime_scope() { var builder = new ContainerBuilder(); builder.RegisterType<MyClass>().InstancePerLifetimeScope(); IContainer container = builder.Build(); var myClass1 = container.Resolve<MyClass>(); var myClass2 = container.Resolve<MyClass>(); ILifetimeScope inner = container.BeginLifetimeScope(); var myClass3 = inner.Resolve<MyClass>(); var myClass4 = inner.Resolve<MyClass>(); Assert.Equal(myClass1,myClass2); Assert.NotEqual(myClass2,myClass3); Assert.Equal(myClass3,myClass4); }
[Fact] public void life_time_and_dispose() { var builder = new ContainerBuilder(); builder.RegisterType<Disposable>(); using (IContainer container = builder.Build()) { var outInstance = container.Resolve<Disposable>(new NamedParameter("name", "out")); using(var inner = container.BeginLifetimeScope()) { var inInstance = container.Resolve<Disposable>(new NamedParameter("name", "in")); }//inInstance dispose here }//out dispose here }
4.过滤器(转:https://www.cnblogs.com/niklai/p/5676632.html)
下图展示了Asp.Net Core MVC框架默认实现的过滤器的执行顺序:
Authorization Filters:身份验证过滤器,处在整个过滤器通道的最顶层。对应的类型为: AuthorizeAttribute.cs 对应的接口有同步和异步两个版本: IAuthorizationFilter.cs 、 IAsyncAuthorizationFilter.cs
Resource Filters:资源过滤器。因为所有的请求和响应都将经过这个过滤器,所以在这一层可以实现类似缓存的功能。对应的接口有同步和异步两个版本: IResourceFilter.cs 、 IAsyncResourceFilter.cs
Action Filters:方法过滤器。在控制器的Action方法执行之前和之后被调用,一个很常用的过滤器。对应的接口有同步和异步两个版本: IActionFilter.cs 、 IAsyncActionFilter.cs
Exception Filters:异常过滤器。当Action方法执行过程中出现了未处理的异常,将会进入这个过滤器进行统一处理,也是一个很常用的过滤器。对应的接口有同步和异步两个版本: IExceptionFilter.cs 、 IAsyncExceptionFilter.cs
Result Filters:返回值过滤器。当Action方法执行完成的结果在组装或者序列化前后被调用。对应的接口有同步和异步两个版本: IResultFilter.cs 、 IAsyncResultFilter.cs
5.中间件(转https://www.cnblogs.com/niklai/p/5665272.html)
Asp.Net Core,管道模型流程图
IHttpModule和IHttpHandler不复存在,取而代之的是一个个中间件(Middleware)。
Server将接收到的请求直接向后传递,依次经过每一个中间件进行处理,然后由最后一个中间件处理并生成响应内容后回传,再反向依次经过每个中间件,直到由Server发送出去。
中间件就像一层一层的“滤网”,过滤所有的请求和相应。这一设计非常适用于“请求-响应”这样的场景——消息从管道头流入最后反向流出。
接下来将演示在Asp.Net Core里如何实现中间件功能。
IHttpModule和IHttpHandler不复存在,取而代之的是一个个中间件(Middleware)。
Server将接收到的请求直接向后传递,依次经过每一个中间件进行处理,然后由最后一个中间件处理并生成响应内容后回传,再反向依次经过每个中间件,直到由Server发送出去。
中间件就像一层一层的“滤网”,过滤所有的请求和相应。这一设计非常适用于“请求-响应”这样的场景——消息从管道头流入最后反向流出。
接下来将演示在Asp.Net Core里如何实现中间件功能。
Middleware
Middleware支持Run、Use和Map三种方法进行注册,下面将展示每一种方法的使用方式。
Run方法
所有需要实现的自定义管道都要在 Startup.cs 的 Configure 方法里添加注册。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定义中间件 app.Run(async context => { await context.Response.WriteAsync("Hello World!"); }); // 添加MVC中间件 //app.UseMvc(); }
启动调试,访问地址 http://localhost:5000/ ,页面显示Hello World!字样
再次添加一个Run方法
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定义中间件 app.Run(async context => { await context.Response.WriteAsync("Hello World!"); }); app.Run(async context => { await context.Response.WriteAsync("Hello World too!"); }); // 添加MVC中间件 //app.UseMvc(); }
启动调试,再次访问发现页面上只有Hello World!字样。
原因是:Run的这种用法表示注册的此中间件为管道内的最后一个中间件,由它处理完请求后直接返回。
Use方法
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定义中间件 app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World!"); }); // 添加MVC中间件 //app.UseMvc(); }
启动调试,访问页面同样显示Hello World!字样。我们发现使用Use方法替代Run方法,一样可以实现同样的功能。
再次添加一个Use方法,将原来的Use方法内容稍作调整,尝试实现页面显示两个Hello World!字样。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定义中间件 app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World!"); await next(); }); app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World too!"); }); // 添加MVC中间件 //app.UseMvc(); }
将两个Use方法换个顺序,稍微调整一下内容,再次启动调试,访问页面,发现字样输出顺序也发生了变化。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); HelloworldMiddleware.cs // 添加自定义中间件 app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World too!"); await next(); }); app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World!"); }); // 添加MVC中间件 //app.UseMvc(); }
从上面的例子可以发现,通过Use方法注册的中间件,如果不调用next方法,效果等同于Run方法。当调用next方法后,此中间件处理完后将请求传递下去,由后续的中间件继续处理。
当注册中间件顺序不一样时,处理的顺序也不一样,这一点很重要,当注册的自定义中间件数量较多时,需要考虑哪些中间件先处理请求,哪些中间件后处理请求。
另外,我们可以将中间件单独写成独立的类,通过UseMiddleware方法同样可以完成注册。下面将通过独立的中间件类重写上面的演示功能。
新建两个中间件类: HelloworldMiddleware.cs 、 HelloworldTooMiddleware.cs
using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace WebApiFrame.Core.Middlewares { public class HelloworldMiddleware { private readonly RequestDelegate _next; public HelloworldMiddleware(RequestDelegate next){ _next = next; } public async Task Invoke(HttpContext context){ await context.Response.WriteAsync("Hello World!"); await _next(context); } } } HelloworldMiddleware.cs
using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace WebApiFrame.Core.Middlewares { public class HelloworldTooMiddleware { private readonly RequestDelegate _next; public HelloworldTooMiddleware(RequestDelegate next){ _next = next; } public async Task Invoke(HttpContext context){ await context.Response.WriteAsync("Hello World too!"); } } } HelloworldTooMiddleware.cs
修改 Startup.cs 的Configure方法内容
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定义中间件 app.UseMiddleware<HelloworldMiddleware>(); app.UseMiddleware<HelloworldTooMiddleware>(); // 添加MVC中间件 //app.UseMvc(); }
启动调试,访问页面,可以看到同样的效果。
Map方法
Map方法主要通过请求路径和其他自定义条件过滤来指定注册的中间件,看起来更像一个路由。
修改 Startup.cs 的Configure方法内容,增加静态方法MapTest
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定义中间件 app.Map("/test", MapTest); // 添加MVC中间件 //app.UseMvc(); } private static void MapTest(IApplicationBuilder app){ app.Run(async context => { await context.Response.WriteAsync("Url is " + context.Request.PathBase.ToString()); }); }
启动调试,访问路径 http://localhost:5000/test ,页面显示如下内容
但是访问其他路径时,页面没有内容显示。从这个可以看到,Map方法通过类似路由的机制,将特定的Url地址请求引导到固定的方法里,由特定的中间件处理。
另外,Map方法还可以实现多级Url“路由”,其实就是Map方法的嵌套使用
// 添加自定义中间件 app.Map("/level1", lv1App => { app.Map("/level1.1", lv11App => { // /level1/level1.1 }); app.Map("/level1.2", lv12App => { // /level1/level1.2 }); });
也可以通过MapWhen方法使用自定义条件进行“路由”
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定义中间件 app.MapWhen(context => { return context.Request.Query.ContainsKey("a"); }, MapTest); // 添加MVC中间件 //app.UseMvc(); } private static void MapTest(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync($"Url is {context.Request.Path.ToString()}{context.Request.QueryString.Value}"); }); }
启动调试,访问路径 http://localhost:5000/path?a=1&b=2 ,页面显示如下内容
只有当请求参数中含有a时,页面才正常显示内容。
其他内置的中间件
Asp.Net Core框架内置了几个中间件
6.路由(转https://www.cnblogs.com/tianma3798/p/6920638.html)
1.API定义
/* * API 定义如下 * GET api/menu 获取菜单列表 * POST api/menu 添加模块 * PUT api/menu 修改模块 * PATCH api/menu 修改菜单信息 * DELETE api/menu 删除模块 */
2.后台代码 :
MenuModelContext _Context = new MenuModelContext(); /// <summary> /// 获取列表 /// </summary> /// <returns></returns> [HttpGet] public IEnumerable<Menu> Get() { List<Menu> list = _Context.Menu.ToList(); return list; } /// <summary> /// 添加模块对象 /// </summary> /// <param name="m"></param> /// <returns></returns> [HttpPost] public bool Add(Model m) { try { m.AddTime = DateTime.Now; _Context.Model.Add(m); _Context.SaveChanges(); return true; } catch (Exception ex) { return false; } } /// <summary> /// 修改模块 /// </summary> /// <param name="m"></param> /// <returns></returns> [HttpPut] public bool Update(Model m) { try { Model oldModel = _Context.Model.Find(m.ModelId); oldModel.ModelName = m.ModelName; oldModel.SortNumber = m.SortNumber; _Context.SaveChanges(); return true; } catch (Exception ex) { return false; } } /// <summary> /// 修改菜单对象 /// </summary> /// <param name="m"></param> /// <returns></returns> [HttpPatch] public IActionResult Update(Menu m) { try { Menu oldMenu = _Context.Menu.Find(m.MenuId); if (oldMenu == null) return NotFound("你要访问的菜单不存在或已经删除"); oldMenu.MenuName = m.MenuName; oldMenu.SortNumber = m.SortNumber; oldMenu.ModelId = m.ModelId; _Context.SaveChanges(); return Ok(); } catch (Exception ex) { return Content(ex.Message); } } /// <summary> /// 删除模块 /// </summary> /// <param name="ids"></param> /// <returns></returns> [HttpDelete] public IActionResult Delete(string ids) { try { if (string.IsNullOrEmpty(ids)) throw new Exception("获取id参数失败"); List<int> idList = ids.Split(',').Select(q => Convert.ToInt32(q)).ToList(); List<Model> list = _Context.Model.Where(q => idList.Contains(q.ModelId)).ToList(); _Context.Model.RemoveRange(list); int count = _Context.SaveChanges(); //使用OkObjectResult 前台jquery自动解析为object对象,不需要进行反序列化处理 //返回的不是字符串 return Ok(new { msg = $"删除成功,总共删除{count}条数据" }); } catch (Exception ex) { //使用ContentResult返回字符串处理 return Content(ex.Message); } }
3.jQuery ajax代码
//Get获取列表数据 function testOne() { $.get(urlHelper.getApi('menu'), {}, function (data) { console.info(data); var menu1 = new Vue({ el: '#menu1', data: { result: data } }); }) } testOne(); //添加菜单 var example2 = new Vue({ el: '#example-2', data: { name:'添加菜单' }, //在 methods 对象中定义方法 methods: { addMenu: function (event) { //使用 Post提交添加菜单 var _this = this; this.name = '正在提交...'; $.post(urlHelper.getApi('menu'), { ModelName: '测试菜单5', SortNumber:5 }, function (data) { console.info(data); _this.name = '提交成功'; }); }, updateModel: function (event) { //使用put提交修改模块 var _this = this; $.ajax({ url: urlHelper.getApi('menu'), type: 'put', data: { ModelId: '4', ModelName: '模块abc', SortNumber: 4 }, success: function (data) { console.info(data); if (data == true) alert('修改成功'); else alert('修改失败'); } }); } } }); //修改菜单、删除模块 var btngroup1 = new Vue({ el: '#btngroup1', data: { name: '修改菜单', name1: '删除模块' }, methods: { updateMenu: function (e) { var _this = this; //使用patch 方式修改菜单 $.ajax({ url: urlHelper.getApi('menu'), type:'patch', data: { MenuID: 1, MenuName: '测试菜单One', SortNumber: 100, ModelID:2 }, success: function (data) { console.info(data); } }); }, deleteMenu: function (e) { //使用delete 提交方式删除模块 $.ajax({ url: urlHelper.getApi('menu'), type: 'delete', data: { ids:[1003] }, success: function (data) { console.info(data); }, error: function (data) { console.info(data); } }); } } });
根据HttpMethod的Template路由示例
1.API定义
/* * API 定义 * GET api/menu/{id} 获取指定ID的菜单对象 * GET api/menu/getmodel 获取模块列表内容 */
[HttpGet("{id}")] public IActionResult Get(int ID) { Menu m = _Context.Menu.Find(ID); if (m == null) return NotFound(); return Json(m); } //特别说明:路由中的Template的值不可以包含斜杠/ [HttpGet("getmodel")] public IActionResult GetModel() { List<Model> list = _Context.Model.ToList(); return Json(list); }
Jquery 的ajax代码
//其他Get方式测试 var btngroup2 = new Vue({ el: '#btngroup2', data: { name: '获取菜单对象', name1: '获取模块列表', item: {} //Vue的对象绑定,没有的情况下需要一个空对象,不然报错 }, methods: { getMenu: function (e) { var _this = this; //链接地址格式 :http://localhost:50000/api/menu/1/ $.get(urlHelper.getApi('menu','1'), { }, function (data) { console.info(data); _this.item = data; }); }, getModel: function (e) { var _this = this; $.get(urlHelper.getApi('menu', 'getmodel'), {}, function (data) { console.info(data); }) } } });
7.Startup
/// <summary> /// 此方法由运行时调用。使用此方法向容器添加服务。 /// </summary> /// <param name="services">For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940</param> /// <returns>DI容器</returns> public IServiceProvider ConfigureServices(IServiceCollection services) { //添加MVC services.AddMvc( // 配置异常过滤器 config => { config.Filters.Add(typeof(CustomExceptionFilter)); } ) // 设置json序列化方式 .AddJsonOptions(mvcJsonOptions => { //忽略循环引用 mvcJsonOptions.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //不使用驼峰样式的key mvcJsonOptions.SerializerSettings.ContractResolver = new DefaultContractResolver(); //设置时间格式 mvcJsonOptions.SerializerSettings.DateFormatString = Const.yyyyMMddHHmmss; }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddCors(options => { options.AddPolicy("AllowSpecificOrigins", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); }); }); // 注册服务并且实例化AutoFac替换默认容器 var containerBuilder = new ContainerBuilder(); //实例化 AutoFac 容器 // 注册用户服务 containerBuilder.RegisterType<UserService>().As<IUserService>(); containerBuilder.Populate(services); ApplicationContainer = containerBuilder.Build(); return new AutofacServiceProvider(ApplicationContainer); //第三方IOC接管 core内置DI容器 }
/// <summary> /// 此方法由运行时调用。使用此方法配置HTTP请求管道。 /// </summary> /// <param name="app">app</param> /// <param name="env">env</param> public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //if (env.IsDevelopment()) //{ // app.UseDeveloperExceptionPage(); //} //app.UseExceptionHandler( // options => { // options.Run( // async context => // { // context.Response.StatusCode = (int)HttpStatusCode.OK; // context.Response.ContentType = "text/html"; // var ex = context.Features.Get<IExceptionHandlerFeature>(); // if (ex != null) // { // var err = $"<h1>Error: {ex.Error.Message}</h1>{ex.Error.StackTrace }"; // await context.Response.WriteAsync(err).ConfigureAwait(false); // } // }); // } //); //启动跨域 app.UseCors("AllowSpecificOrigins"); //注入MVC路由 app.UseMvc(); }