Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >ASP.NET Core MVC应用模型的构建[2]: 定制应用模型

ASP.NET Core MVC应用模型的构建[2]: 定制应用模型

作者头像
蒋金楠
发布于 2024-02-28 00:17:47
发布于 2024-02-28 00:17:47
17200
代码可运行
举报
文章被收录于专栏:大内老A大内老A
运行总次数:0
代码可运行

在对应用模型的基本构建方式具有大致的了解之后,我们来系统地认识一下描述应用模型的ApplicationModel类型。对于一个描述MVC应用模型的ApplicationModel对象来说,它承载的元数据绝大部分是由默认注册的DefaultApplicationModelProvider对象提供的,在接下来针对ApplicationModel及其相关类型(ControllerModel、ActionModel和ParameterModel等)的介绍中,我们还会着重介绍DefaultApplicationModelProvider对象采用怎样的方式提取并设置这些元数据。

一、几个重要的接口

在正式介绍ApplicationModel及其相关类型的定义之前,我们先来认识如下几个重要的接口,针对不同模型节点的类型分别实现了这些接口的一个或者多个。认识这些接口有助于我们更好地理解应用模型的层次结构以及每种模型节点的用途。

IPropertyModel

为了让应用模型的构建方式具有更好的扩展性,ApplicationModel类型以及描述其他描述模型节点的类型(ControllerModel、ActionModel和ParameterModel等)都提供了一个字典类型的Properties属性,自定义的IApplicationModelProvider实现类型以及各种形式的约定类型都可以将任意属性存储到这个字典中。这个Properties属性是对IPropertyModel接口的实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IPropertyModel
{
    IDictionary<object, object> Properties { get; }
}

ICommonModel

描述MVC应用模型的ApplicationModel对象由描述所有Controller类型的ControllerModel对象组成,而ControllerModel对象则通过描述其Action方法和属性的ActionModel和PropertyModel对下组成。这三种分别描述类型、方法和属性的模型节点本质上都是对一个MemberInfo对象的封装,描述对应节点的元数据主要由标注在它们上面的特性来提供,所以标注的特性成了这些模型节点重要的元素。除此之外,这些模型节点还应该具有一个唯一的命名。综上这些元素被统一定义在如下这个ICommonModel接口中,该接口派生于IPropertyModel接口。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface ICommonModel : IPropertyModel
{
    MemberInfo 		        MemberInfo { get; }
    string 			Name { get; }
    IReadOnlyList<object> 	Attributes { get; }
}

IFilterModel

针对MVC应用的请求总是被路由到某个匹配的Action,针对请求的处理体现在对目标Action的执行。这里所谓的“执行Action”不仅仅包括针对目标方法的执行,还需要执行应用在该Action上的一系列过滤器。过滤器使我们可以很容易地“干预”针对目标Action的执行流程,它们可以直接注册到Action方法上,也可以注册到Controller类型,甚至可以在应用范围进行全局注册,所以MVC框架为这些包含过滤器注册的模型节点(ApplicationModel、ControllerModel和ActionModel)定义了如下这个IFilterModel接口。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IFilterModel
{
    IList<IFilterMetadata> 	Filters { get; }
}

如上面的代码片段所示,IFilterModel接口定义了唯一的Filters属性返回一个IFilterMetadata对象的列表,IFilterMetadata接口是对过滤器元数据的描述。

IApiExplorerModel

当我们在面向Controller的MVC编程模型上开发API的时候,我们希望应用能够提供在API层面的元数据。这些面向开发人员的元数据告诉我们当前应用提供了怎样的API终结点,每个终结点的路径是什么、支持何种HTTP方法、需要怎样的输入、输入和响应具有怎样的结构等。MVC框架专门提供了一个名为“ApiExplorer”的模块来完成针对API元数据的导出任务。我们可以利用API元数据自动生成在线开发文档(比如著名的Swagger就是这么干的),也可以针对不同的语言生成调用API的客户端代码。

如果说ActionDescriptor对象是Action面向运行时的描述,那么Action面向API的描述就体现为一个ApiDescription对象。我们可以在Controller类型或者具体的Action方法上标注实现IApiDescriptionGroupNameProvider接口的特性对ApiDescription对象进行分组(设置GroupName属性),也可以标注实现了IApiDescriptionVisibilityProvider接口的特性控制对应API的可见性(如果IgnoreApi属性设置为True,ApiExplorer将不会生成对应的ApiDescription对象)。如下所示的ApiExplorerSettingsAttribute特性是对这两个接口的实现。IApiExplorerModel接口定义的ApiExplorer属性返回的ApiExplorerModel对象于此对应。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IApiDescriptionGroupNameProvider
{
    string GroupName { get; }
}
public interface IApiDescriptionVisibilityProvider
{
    bool IgnoreApi { get; }
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited=true)]
public class ApiExplorerSettingsAttribute : Attribute, IApiDescriptionGroupNameProvider, IApiDescriptionVisibilityProvider
{
    public string 	GroupName { get; set; }
    public bool 	IgnoreApi { get; set; }
}

针对API分组和可见性的设置体现在面向应用(ApplicationModel)、Controller类型(ControllerModel)和Action方法(ActionModel)的模型节点上,所以它们都会实现如下这个IApiExplorerModel,两个设置体现在ApiExplorer返回的ApiExplorerModel对象上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IApiExplorerModel
{
    ApiExplorerModel 	ApiExplorer { get; set; }
}
public class ApiExplorerModel
{
    public bool? 	IsVisible { get; set; }
    public string 	GroupName { get; set; }
}

IBindingModel

MVC框架采用“模型绑定”的机制来绑定目标Action方法的参数列表和定义在Controller类型中相应的属性,所以描述参数的ParameterModel对象和描述Controller属性的PropertyModel对象需要提供服务于模型绑定的元数据。MVC为这两种模型节点定义了如下这个IBindingModel接口,它利用BindingInfo属性返回的BindingInfo对象提供绑定元数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IBindingModel
{
    BindingInfo BindingInfo { get; set; }
}

二、ApplicationModel

如下所示的是描述应用模型的ApplicationModel类型的定义,它的核心是Controllers属性返回的一组ControllerModel对象。该类型实现了IPropertyModel、IFilterModel和IApiExplorerModel接口,DefaultApplicationModelProvider对象只会提取在应用级别全局注册的过滤器,并生成相应的IFilterMetadata对象添加到Filters属性中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ApplicationModel : IPropertyModel, IFilterModel, IApiExplorerModel
{
    public IList<ControllerModel> 		Controllers { get; }
    public IList<IFilterMetadata> 		Filters { get; }
    public ApiExplorerModel 			ApiExplorer { get; set; }
    public IDictionary<object, object> 	Properties { get; }
}

在了解了DefaultApplicationModelProvider对象针对应用模型的大致构建规则之后,我们利用一个简单的实例演示来对此做一个验证。由于构建应用模型的ApplicationModelFactory是一个内部类型,所以我们在作为演示程序的MVC应用中定义了如下这个ApplicationModelProducer类型。如代码片段所示,它会利用注入的IServiceProvider对象来提供ApplicationModelFactory对象。在定义的Create方法中,ApplicationModelProducer根据反射的方式调用ApplicationModelFactory的CreateApplicationModel方法根据指定的Controller类型创建出描述应用模型的ApplicationModel对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ApplicationModelProducer
{
    private readonly Func<Type[], ApplicationModel> _factory;
    public ApplicationModelProducer(IServiceProvider serviceProvider)
    {
        var assemblyName = new AssemblyName("Microsoft.AspNetCore.Mvc.Core");
        var assemly = Assembly.Load(assemblyName);
        var typeName ="Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModelFactory";
        var factoryType = assemly.GetTypes().Single(it => it.FullName ==typeName);
        var factory = serviceProvider.GetService(factoryType);
        var method = factoryType.GetMethod("CreateApplicationModel");
        _factory = controlerTypes =>
        {
            var typeInfos = controlerTypes.Select(it => it.GetTypeInfo());
            return (ApplicationModel)method.Invoke(factory, new object[] { typeInfos });
        };
    }
    public ApplicationModel Create(params Type[] controllerTypes) => _factory(controllerTypes);
}

为了验证针对全局过滤器的注册,我们定义了如下这个FoobarAttribute特性。如代码片段所示,FoobarAttribute派生于ActionFilterAttribute特性。从标注的AttributeUsage特性来看,多个FoobarAttribute特性可以同时标注到Controller类型或者Action方法上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[AttributeUsage(AttributeTargets.Class| AttributeTargets.Method, AllowMultiple = true)]
public class FoobarAttribute : ActionFilterAttribute
{
}

在如下所示的应用承载程序中,我们调用IWebHostBuilder接口的ConfigureServices方法添加了针对ApplicationModelProducer类型的服务注册。在调用AddControllersWithViews扩展方法的过程中,我们创建了一个FoobarAttribute对象并将它添加到MvcOptions对象的Filters属性中,意味着我们在应用范围内全局注册了这个FoobarAttribute过滤器。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Program
{
    static void Main()
    {
        Host.CreateDefaultBuilder()
            .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder
                .ConfigureServices(services => services
                    .AddSingleton<ApplicationModelProducer>()
                    .AddRouting()
                    .AddControllersWithViews(options=>options.Filters.Add(new FoobarAttribute())))
                .Configure(app => app
                    .UseRouting()
                    .UseEndpoints(endpoints => endpoints.MapControllers())))
            .Build()
            .Run();
    }
}

我们在定义了如下三个用于测试的Controller类型(FooController、BarController和BazController)。我们将用于呈现主页的Action方法定义在HomeController类型中。简单起见,我们直接将ApplicationModelProducer对象注入到Index方法中,并通过标注的FromServicesAttribute特性指示利用注册的服务来绑定该参数。Index方法利用这个ApplicationModelProducer对象构建出根据三个测试Controller类型创建的ApplicationModel对象,并将其作为Model呈现在默认View中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class FooController
{
    public void Index() => throw new NotImplementedException();
}
public class BarController
{
    public void Index() => throw new NotImplementedException();
}
public class BazController
{
    public void Index() => throw new NotImplementedException();
}

public class HomeController: Controller
{
    [HttpGet("/")]
    public IActionResult Index([FromServices]ApplicationModelProducer producer)
    {
        var applicationModel = producer.Create(typeof(FooController), typeof(BarController), typeof(BazController));
        return View(applicationModel);
    }
}

如下所示的就是Action方法Index对应View的定义。如代码片段所示,这是一个Model类型为ApplicationModel的强类型View。在这个View中,我们将构成ApplicationModel对象的所有ControllerModel的名称、过滤器的类型以及ApiExplorer相关的两个对象以表格的形式呈现出来。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@model Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel
@{
    var controllers = Model.Controllers;
    var filters = Model.Filters;
}
<html>
<head>
    <title>Application</title>
</head>
<body>
    <table border="1" cellpadding="0" cellspacing="0">
        <tr>
            <td rowspan="@controllers.Count">Controllers</td>
            <td>@controllers[0].ControllerName</td>
        </tr>
        @for (int index = 1; index < controllers.Count; index++)
        {
            <tr><td>@controllers[index].ControllerName</td></tr>
        }
        <tr>
            <td rowspan="@filters.Count">Filters</td>
            <td>@filters[0].GetType().Name</td>
        </tr>
        @for (int index = 1; index < filters.Count; index++)
        {
            <tr><td>@filters[index].GetType().Name</td></tr>
        }
        <tr>
            <td rowspan="2">ApiExplorer</td>
            <td>IsVisible = @Model.ApiExplorer.IsVisible </td>
        </tr>
        <tr><td>GroupName = @Model.ApiExplorer.GroupName </td></tr>

    </table>
</body>
</html>

演示程序启动之后,如果利用浏览器访问其根路径,我们会得到如图1所示的输出结果。我们可以从输出结果中看到组成ApplicationModel对象的三个Controller的名称。ApplicationModel对象的Filters属性列表中包含三个全局过滤器,除了我们显式注册的FoobarAttribute特性之外,还具有一个在不支持提供媒体类型情况下对请求进行处理的UnsupportedContentTypeFilter过滤器,它是在AddMvcCore扩展方法中注册的。另一个用来保存临时数据的SaveTempDataAttribute特性则是通过AddControllersWithViews扩展方法注册的。默认下,ApplicationModel对象的ApiExplorer属性返回的ApiExplorerModel对象并没有做相应的设置。

clip_image002
clip_image002

图1 应用模型的默认构建规则

三、自定义IApplicationModelProvider

由于MVC框架针对目标Action的处理行为完全由描述该Action的ActionDescriptor对象决定,而最初的元数据则来源于应用模型,所以有时候一些针对请求流程的控制需要间接地利用针对应用模型的定制来实现。通过前面的内容,我们知道应用模型的定制可以通过注册自定义的IApplicationModelProvider实现类型,接下来我们就来做相应的演示。

通过上面演示的势力可以看出,默认情况下构建出来的ApplicationModel对象的ApiExplorer属性并没有作具体的设置,接下来我们将此设置实现在一个IApplicationModelProvider实现类型中。具体来说,我们希望在MVC应用所在项目的程序集上标注如下这个ApiExplorerAttribute特性来设置与ApiExplorer相关的两个属性。我们将针对该特性的标注按照如下的方式定义在Program.cs中,该特性将GroupName设置为 “Foobar” 。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[AttributeUsage(AttributeTargets.Assembly)]
public class ApiExplorerAttribute:Attribute
{
    public bool 	IsVisible => true;
    public string 	GroupName { get; set; }
}

[assembly: ApiExplorer(GroupName = "Foobar")]

针对ApiExplorerAttribute特性的解析以及基于该特性设置对应用模型的定制实现在如下这个ApiExplorerApplicationModelProvider类型中。如代码片段所示,该类型的构造函数中注入了代表承载环境的IHostEnvironment对象,我们利用它得到当前应用的名称,并将它作为程序集名称得到标注的ApiExplorerAttribute特性,进而得到基于ApiExplorer的设置。在实现的OnProvidersExecuting方法中,我们将相关设置应用到ApplicationModel对象上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ApiExplorerApplicationModelProvider : IApplicationModelProvider
{
    private readonly bool? 	_isVisible;
    private readonly string 	_groupName;

    public int Order => -1000;

    public ApiExplorerApplicationModelProvider(IHostEnvironment hostEnvironment)
    {
        var assembly = Assembly.Load(new AssemblyName(hostEnvironment.ApplicationName));
        var attribute = assembly.GetCustomAttribute<ApiExplorerAttribute>();
        _isVisible = attribute?.IsVisible;
        _groupName = attribute?.GroupName;
    }
    public void OnProvidersExecuted(ApplicationModelProviderContext context) { }

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        context.Result.ApiExplorer.GroupName??= _groupName;
        context.Result.ApiExplorer.IsVisible ??= _isVisible;
    }
}

为了上面这个自定义的ApiExplorerApplicationModelProvider类型,我们对应用承载程序做了如下的改动。如代码片段所示,我们只需要调用IWebHostBuilder的ConfigureServices方法将该类型作为服务注册到依赖注入框架中即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Program
{
    static void Main()
    {
        Host.CreateDefaultBuilder()
            .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder
                .ConfigureServices(services => services
                    .AddSingleton<IApplicationModelProvider, ApiExplorerApplicationModelProvider>()
                    .AddSingleton<ApplicationModelProducer>()
                    .AddRouting()
                    .AddControllersWithViews(options=>options.Filters.Add(new FoobarAttribute())))
                .Configure(app => app
                    .UseRouting()
                    .UseEndpoints(endpoints => endpoints.MapControllers())))
            .Build()
            .Run();
    }
}

改动后的演示程序启动后,我们利用浏览器访问应用的主页,可以得到如图2所示的输出结果。从浏览器上的输出结果可以看出,对于ApplicationModelFactory最终构建的ApplicationModel对象来说,它的ApiExplorer属性这次得到了相应的设置。

clip_image004
clip_image004

图2 注册自定义IApplicationModelProvider实现类型定制应用模型

四、自定义IApplicationModelConvention

除了利用自定义的IApplicationModelProvider实现类型对应用模型进行定制之外,我们还可以注册各种类型的约定达到相同的目的。上面演示的针对ApiExplorer相关设置的定制完全可以利用如下这个ApiExplorerConvention类型来完成。如代码片段所示,ApiExplorerConvention类型实现了IApplicationModelConvention接口,我们直接在构造函数中指定ApiExplorer相关的两个属性,并在实现的Apply方法中将其应用到表示应用模型的ApplicationModel对象上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ApiExplorerConvention : IApplicationModelConvention
{
    private readonly bool? 	_isVisible;
    private readonly string 	_groupName;

    public ApiExplorerConvention(bool? isVisible, string groupName)
    {
        _isVisible = isVisible;
        _groupName = groupName;
    }

    public void Apply(ApplicationModel application)
    {
        application.ApiExplorer.IsVisible ??= _isVisible;
        application.ApiExplorer.GroupName ??= _groupName;
    }
}

用于定制应用模型的各种约定需要注册到代表MVC应用配置选项的MvcOptions对象上,所以我们需要对应用承载程序作相应的修改。如下面你代码片段所示,在调用IServiceCollection接口的AddControllersWithViews扩展方法是,我们创建了一个ApiExplorerConvention对象,并将其添加到作为配置选项的MvcOptions对象的Conventions属性上。改动后的演示程序启动后,我们利用浏览器访问应用的主页依然可以得到如图2所示的输出结果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Program
{
    static void Main()
    {
        Host.CreateDefaultBuilder()
            .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder
                .ConfigureServices(services => services
                    .AddSingleton<ApplicationModelProducer>()
                    .AddRouting()
                    .AddControllersWithViews(options=>
                    {
                        options.Filters.Add(new GlobalFilter());
                        options.Conventions.Add(new ApiExplorerConvention(true, "Foobar"));
                    }))
                .Configure(app => app
                    .UseRouting()
                    .UseEndpoints(endpoints => endpoints.MapControllers())))
            .Build()
            .Run();
    }
}

ASP.NET Core MVC应用模型的构建[1]: 应用的蓝图

ASP.NET Core MVC应用模型的构建[2]: 应用模型

ASP.NET Core MVC应用模型的构建3: Controller模型

ASP.NET Core MVC应用模型的构建4: Action模型

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ASP.NET Core MVC应用模型的构建[3]: Controller的收集
从编程的角度来看,一个MVC应用是由一系列Controller类型构建而成的,所以对于一个代表应用模型的ApplicationModel对象来说,它的核心就是Controllers属性返回的一组ControllerModel对象,每个ControllerModel对象是应用模型针对Controller类型的描述。
蒋金楠
2024/02/29
1280
ASP.NET Core MVC应用模型的构建[3]: Controller的收集
ASP.NET Core MVC应用模型的构建[4]: Action的选择
ControllerModel类型的Actions属性包含一组描述有效Action方法的ActionModel对象。对于定义在Controller类型中的所有方法,究竟哪些方法才能成为有效的Action方法呢?所以在正式介绍ActionModel类型之前,我们先来聊聊Action方法的选择规则。
蒋金楠
2024/03/01
1650
ASP.NET Core MVC应用模型的构建[4]: Action的选择
5. abp集成asp.net core
参照前篇《4. abp中的asp.net core模块剖析》,首先放张图,这也是asp.net core框架上MVC模块的扩展点
Ryan_OVO
2023/10/19
4520
5. abp集成asp.net core
ASP.NET Core MVC应用模型的构建[1]: 应用的蓝图
我个人觉得这是ASP.NET Core MVC框架体系最核心的部分。原因很简单,MVC框架建立在ASP.NET Core路由终结点上,它最终的目的就是将每个Action方法映射为一个或者多个路由终结点,路由终结点根据附加在Action上的若干元数据构建而成。为了构建描述当前应用所有Action的元数据,MVC框架会提取出定义在当前应用范围内的所有Controller类型,并进一步构建出基于Controller的应用模型。应用模型不仅仅是构建Action元数据的基础,承载API的应用还可以利用它自动生成API开发文档,一些工具甚至可以利用应用模型自动生成消费API的客户端代码。这篇文章大概是两年之前写的,可能一些技术细节在最新版本的ASP.NET Core MVC已经发生了改变,但总体设计依然如此。
蒋金楠
2024/02/27
2080
ASP.NET Core MVC应用模型的构建[1]: 应用的蓝图
【asp.net core】实现动态 Web API
远程工作已经一个月了,最近也算是比较闲,每天早上起床打个卡,快速弄完当天要做的工作之后就快乐摸鱼去了。之前在用 ABP 框架(旧版)的时候就觉得应用服务层写起来真的爽,为什么实现了个 IApplicationService 的空接口就可以变成 Web API,可惜的是之前一直没空去研究这一块的原理及其实现,园子里也找不到相关实现原理的文章(旧版 ABP 的倒是有,但是 asp.net core 无法参考)。最近闲起来,就看了一下 abp vnext 的源码,并且也参考了一下晓晨Master 介绍的 Panda.DynamicWebApi。我自己也简单实现了一遍动态 Web API,不禁感叹 asp.net core 设计之精妙。
李明成
2020/03/18
2.8K0
【asp.net core】实现动态 Web API
[ASP.NET Core MVC] 如何实现运行时动态定义Controller类型?
昨天有个朋友在微信上问我一个问题:他希望通过动态脚本的形式实现对ASP.NET Core MVC应用的扩展,比如在程序运行过程中上传一段C#脚本将其中定义的Controller类型注册到应用中,问我是否有好解决方案。我当时在外边,回复不太方便,所以只给他说了两个接口/类型:IActionDescriptorProvider和ApplicationPartManager。这是一个挺有意思的问题,所以回家后通过两种方案实现了这个需求。源代码从这里下载。
蒋金楠
2020/04/08
1.5K1
[ASP.NET Core MVC] 如何实现运行时动态定义Controller类型?
在Asp.Net Core中使用ModelConvention实现全局过滤器隔离
这来自于我把项目迁移到Asp.Net Core的过程中碰到一个问题。在一个web程序中同时包含了MVC和WebAPI,现在需要给WebAPI部分单独添加一个接口验证过滤器IActionFilter,常规做法一般是写好过滤器后给需要的控制器挂上这个标签,高级点的做法是注册一个全局过滤器,这样可以避免每次手动添加同时代码也更好管理。注册全局过滤器的方式为:
HOHO
2020/04/27
1.2K0
4. abp中的asp.net core模块剖析
abp通过这三个模块加载并配置了 asp.net core。,最主要的就是AbpAspNetCoreMvcModule模块类,abp如何基于aspnet core构建自己的控制器和AppServices,就是在这个类中。
Ryan_OVO
2023/10/19
2900
深入解析ASP.NET Core MVC应用的模块化设计[上篇]
ASP.NET Core MVC的“模块化”设计使我们可以构成应用的基本单元Controller定义在任意的模块(程序集)中,并在运行时动态加载和卸载。这种为“飞行中的飞机加油”的方案是如何实现的呢?该系列的两篇文章将关注于这个主题,本篇着重介绍“模块化”的总体设计,下篇我们将演示将介绍“分散定义Controller”的N种实现方案。
蒋金楠
2024/03/06
3300
深入解析ASP.NET Core MVC应用的模块化设计[上篇]
[ASP.NET Core 3框架揭秘] 跨平台开发体验: Windows [下篇]
由于ASP.NET Core框架在本质上就是由服务器和中间件构建的消息处理管道,所以在它上面构建的应用开发框架都是建立在某种类型的中间件上,整个ASP.NET Core MVC开发框架就是建立在用来实现路由的EndpointRoutingMiddleware和EndpointMiddleware中间件上。ASP.NET Core MVC利用路由系统为它分发请求,并在此基础上实现针对目标Controller的激活、Action方法的选择和执行,以及最终对于执行结果的响应。在介绍的实例演示中,我们将对上面创建的ASP.NET Core作进一步改造,使之转变成一个MVC应用。
蒋金楠
2019/10/11
2K0
[ASP.NET Core 3框架揭秘] 跨平台开发体验: Windows [下篇]
asp.net core权限模块的快速构建
此处的自定义的特性标记不能继承Attribute,因无法在AdminAuthorizeAttribute中的上下文filterContext.Filters中获取到特性标记(不知道咋取特性标记,所以用这种方式代替,也更为简单 冏) !!!!!!!!!修改: 之前脑袋没有转过弯来,要使过滤器上下文的Filters中发现自定义过滤器需要继承 Attribute, IFilterMetadata
易墨
2018/09/14
1.9K0
asp.net core权限模块的快速构建
【愚公系列】2023年02月 WMS智能仓储系统-007.Swagger接口文档的配置
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
愚公搬代码
2023/03/16
9510
【愚公系列】2023年02月 WMS智能仓储系统-007.Swagger接口文档的配置
ASP.NET Core 错误处理(Handle Errors)
链接:cnblogs.com/xiaoxiaotank/p/15586706.html
郑子铭
2021/12/01
2.1K0
ASP.NET Core 错误处理(Handle Errors)
猿学-讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute
ASP.NET Core MVC 2.1 特意为构建 HTTP API 提供了一些小特性,今天主角就是 ApiControllerAttribute. (注:文章是18年2月份的,所以文章提到了core2.1还没发布)。
黑客联盟
2018/08/18
1K0
猿学-讲一下Asp.net core MVC2.1 里面的 ApiControllerAttribute
Asp.Net Core AuthorizeAttribute 和AuthorizeFilter 跟进及源码解读
IdentityServer4已经分享了一些应用实战的文章,从架构到授权中心的落地应用,也伴随着对IdentityServer4掌握了一些使用规则,但是很多原理性东西还是一知半解,故我这里持续性来带大家一起来解读它的相关源代码,本文先来看看为什么Controller或者Action中添加Authorize或者全局中添加AuthorizeFilter过滤器就可以实现该资源受到保护,需要通过access_token才能通过相关的授权呢?今天我带大家来了解AuthorizeAttribute和AuthorizeFilter的关系及代码解读。
Jlion
2022/04/07
3.7K0
Asp.Net Core AuthorizeAttribute 和AuthorizeFilter 跟进及源码解读
【asp.net core 系列】10 实战之ActionFilter
在上一篇中,我们提到了如何创建一个UnitOfWork并通过ActionFilter设置启用。这一篇我们将简单介绍一下ActionFilter以及如何利用ActionFilter,顺便补齐一下上一篇的工具类。
程序员小高
2020/06/18
6670
C# .NET面试系列七:ASP.NET Core
在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务:
GoodTime
2024/03/08
3730
C# .NET面试系列七:ASP.NET Core
如何使用Serilog.AspNetCore记录ASP.NET Core3.0的MVC属性
在我上篇文章中,我描述了如何配置Serilog的RequestLogging中间件以向Serilog的请求日志摘要中添加其他属性(例如请求主机名或选定的端点名称)。这些属性都在HttpContext中可用,因此可以由中间件本身直接添加。
依乐祝
2020/02/14
3.6K0
如何使用Serilog.AspNetCore记录ASP.NET Core3.0的MVC属性
ASP.NET Core应用的7种依赖注入方式
构成HostBuilderContext上下文的两个核心对象(表示配置的IConfiguration对象和表示承载环境的IHostEnvironment对象)可以直接注入Startup构造函数中进行消费。由于ASP.NET Core应用中的承载环境通过IWebHostEnvironment接口表示,IWebHostEnvironment接口派生于IHostEnvironment接口,所以也可以通过注入IWebHostEnvironment对象的方式得到当前承载环境相关的信息。
蒋金楠
2020/03/26
1.8K0
学习ASP.NET Core,你必须了解无处不在的“依赖注入”
ASP.NET Core的核心是通过一个Server和若干注册的Middleware构成的管道,不论是管道自身的构建,还是Server和Middleware自身的实现,以及构建在这个管道的应用,都需要相应的服务提供支持,ASP.NET Core自身提供了一个DI容器来实现针对服务的注册和消费。换句话说,不只是ASP.NET Core底层框架使用的服务是由这个DI容器来注册和提供,应用级别的服务的注册和提供也需要以来这个DI容器,所以正如本文标题所说的——学习ASP.NET Core,你必须了解无处不在的“依
蒋金楠
2018/01/15
1.2K0
学习ASP.NET Core,你必须了解无处不在的“依赖注入”
推荐阅读
相关推荐
ASP.NET Core MVC应用模型的构建[3]: Controller的收集
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验