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

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

作者头像
蒋金楠
发布于 2024-02-27 01:19:26
发布于 2024-02-27 01:19:26
28100
代码可运行
举报
文章被收录于专栏:大内老A大内老A
运行总次数:0
代码可运行

我个人觉得这是ASP.NET Core MVC框架体系最核心的部分。原因很简单,MVC框架建立在ASP.NET Core路由终结点上,它最终的目的就是将每个Action方法映射为一个或者多个路由终结点,路由终结点根据附加在Action上的若干元数据构建而成。为了构建描述当前应用所有Action的元数据,MVC框架会提取出定义在当前应用范围内的所有Controller类型,并进一步构建出基于Controller的应用模型。应用模型不仅仅是构建Action元数据的基础,承载API的应用还可以利用它自动生成API开发文档,一些工具甚至可以利用应用模型自动生成消费API的客户端代码。这篇文章大概是两年之前写的,可能一些技术细节在最新版本的ASP.NET Core MVC已经发生了改变,但总体设计依然如此。

不论是面向Controller的MVC编程模型,还是面向页面的Razor Pages编程模型,客户端请求访问的目标都是某个Action,所以MVC框架的核心功能就是将请求路由到正确的Action,并通过执行目标Action的方式完成请求当前请求的处理。目标Action应该如何执行由描述它的元数据来决定,而这样的元数据是通过ApplicationModel类型标识的应用模型构建出来的。应用模型为MVC应用构建了一个基于Controller的蓝图,我们先从宏观的角度来看看这张蓝图是如何绘制的。

一、 总体设计

图1基本体现了MVC框架构建应用模型的总体设计。代表使用模型的ApplicationModel对象是通过作为工厂的ApplicationModelFactory对象构建的,但是具体的构建任务却落在注册的一系列IApplicationModelProvider和IApplicationModelConvention对象上。

clip_image002
clip_image002

图1 ApplicationModel的构建模型

具体来说,ApplicationModelFactory工程会先创建一个空的ApplicationModel对象,并利用注册的IApplicationModelProvider对象对这个对象进行完善和修正。在此之后,代表默认约定的一系列IApplicationModelConvention对象会依次被执行,它们会将针对应用模型的约定规则应用到同一个ApplicationModel对象上。经过这两个加工环节之后得到的ApplicationModel最终成为描述应用模型的蓝图。

二、ApplicationModel

表示应用模型的ApplicationModel对象不仅是常见Action元数据的依据,同时还有其他重要的用途。由于ApplicationModel对象绘制了整个应用的蓝图,我们经常不仅可以利用它来生成结构化API文档(比如Swagger),还可以利用它提供的元数据生成调用API的客户端代码。通过ApplicationModel表示的应用模型总体上具有如图2所示的结构:一个ApplicationModel对象包含多个描述Controller的ControllerModel对象,一个ControllerModel包含多个ActionModel和PropertyModel对象,ActionModel和PropertyModel是对定义在Controller类型中的Action方法和属性的描述。表示Action方法的ActionModel对象利用ParameterModel描述其参数。

clip_image004
clip_image004

图2 应用模型总体结构

三、IApplicationModelProvider

软件设计中我们经常会遇到这样的场景:我们需要构建一个由若干不同元素组成的复合对象,不同的组成元素具有不同的构建方式,MVC框架几乎基于采用了同一种模式来处理这样的场景。举个简单的例子:对象Foo需要实现的功能需要委托一组Bar对象来实现。MVC框架针对这种需求大都采用如图3所示模式来实现:Foo先创建一个上下文,并提供必要的输入,然后驱动每个Bar对象在这个上下文中完成各自的处理任务。所有Bar对象针对数据和状态的修改,以及产生的输出均体现在这个共享的上下文中,所有对象最终通过这个上下文就可以得到应有的状态或者所需的输出。

clip_image006
clip_image006

图3 基于共享上下文的多对象协作模式(单操作)

有时候我们甚至可以将Bar对象的操作分成两个步骤进行,比如我们将针对这两个步骤的操作分别命名为Executing和Executed。如图4所示,在创建共享上下文之后,Foo对象先按序执行每一个Bar对象的Executing操作,最后再反向执行每个Bar对象的Executed操作,所有的操作均在同一个上下文中执行。

clip_image008
clip_image008

图4 基于共享上下文的多对象协作模式(两阶段)

了解了上面所述的基于共享上下文的多对象协作对象构建模式之后,读者朋友们对于IApplicationModelProvider接口定义就很好理解了。如下面的代码片段所示,IApplicationModelProvider接口定了Order属性来决定了自身的执行顺序,而OnProvidersExecuting和OnProvidersExecuted方法分别完成针对Action元数据构建的两阶段任务。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IApplicationModelProvider
{
    int Order { get; }
    void OnProvidersExecuted(ApplicationModelProviderContext context);
    void OnProvidersExecuting(ApplicationModelProviderContext context);
}

这里作为构建应用模型的执行上下文通过如下这个ApplicationModelProviderContext类型表示。如代码片段所示,ApplicationModelProviderContext类型定义了两个属性,其中ControllerTypes属性表示的列表提供了当前应用所有有效的Controller类型,而Result属性返回的ApplicationModel对象自然代表“待改造”的应用模型。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ApplicationModelProviderContext
{
    public IEnumerable<TypeInfo> 	ControllerTypes { get; }
    public ApplicationModel 		Result { get; }

    public ApplicationModelProviderContext(IEnumerable<TypeInfo> controllerTypes);
}

MVC框架提供如下所示的几个针对IApplicationModelProvider接口的实现类型。对于最终用于描绘当前MVC应用的ApplicationModel对象,其承载的元数据绝大部分是由DefaultApplicationModelProvider对象提供的。AuthorizationApplicationModelProvider和CorsApplicationModelProvider主要提供针对授权和。而ApiBehaviorApplicationModelProvider则负责提供与API相关的描述信息。这些具体实现类型都是内部类型。

  • DefaultApplicationModelProvider:提供构成应用模型的绝大部分元数据。
  • AuthorizationApplicationModelProvider:提供与授权相关元数据。
  • CorsApplicationModelProvider:提供与跨域资源共享(CORS)相关的元数据。
  • ApiBehaviorApplicationModelProvider:提供与API行为相关的元数据
  • TempDataApplicationModelProvider:为定义在Controller类型中标注了TempDataAttribute特性的属性提供与临时数据保存相关的元数据。
  • ViewDataAttributeApplicationModelProvider:为定义在Controller类型中标注了ViewDataAttribute特性的属性提供与视图数据保存相关的元数据。

IApplicationModelProvider对象针对应用模型的构建是通过ApplicationModelFactory工厂驱动实施的,供这个工厂对象驱策的IApplicationModelProvider对象只需要预先注册到依赖注入容器框架即可。为MVC框架注册基础服务的AddMvcCore扩展方法具有针对DefaultApplicationModelProvider和ApiBehaviorApplicationModelProvider类型以及ApplicationModelFactory的服务注册。IServiceCollection接口的AddControllers扩展方法会添加针对AuthorizationApplicationModelProvider和 CorsApplicationModelProvider类型的注册。针对TempDataApplicationModelProvider ViewDataAttributeApplicationModelProvider类型的服务注册是在IServiceCollection接口的AddControllersWithViews扩展方法中被注册的。

四、IApplicationModelConvention

除了通过在依赖注入框架中注册自定义的IApplicationModelProvider实现类型或者对象方式来定制最终生成的应用模型之外,相同的功能还可以通过注册相应的IApplicationModelConvention对象来完成。顾名思义,IApplicationModelConvention对象旨在帮助我们为应用模型设置一些基于约定的元数据。如下面的代码片段所示,IApplicationModelConvention接口定义了唯一的Apply方法将实现在该方法的约定应用到指定的ApplicationModel对象上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IApplicationModelConvention
{
    void Apply(ApplicationModel application);
}

与IApplicationModelProvider对象或者实现类型的注册不同,供ApplicationModelFactory工厂使用的IApplicationModelConvention对象需要注册到作为MVC应用配置选项的MvcOptions对象上。具体来说,我们需要将注册的IApplicationModelConvention对象添加到MvcOptions如下所示的Conventions属性上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MvcOptions : IEnumerable<ICompatibilitySwitch>
{
    public IList<IApplicationModelConvention> Conventions { get; }
}

五、其他约定

除了利用自定义的IApplicationModelConvention实现类型对整个应用模型进行定制之外,我们还可以针组成应用模型的某种“节点类型”(Controller类型、Action方法、方法参数等)定义相应的约定,这些约定都具有相应的接口。应用模型分别利用ControllerModel、ActionModel和ParameterModel类型来描述Controller类型、Action方法以及方法参数。我们可以分别实现如下的接口定义相应特性,并将它们分别标注到Controller类型、Action方法或者方法参数上,ApplicationModelFactory对象会自动提取这些特性并将它们提供的约定应用到对应类型的模型节点上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IControllerModelConvention
{
    void Apply(ControllerModel controller);
}

public interface IActionModelConvention
{
    void Apply(ActionModel action);
}

public interface IParameterModelConvention
{
    void Apply(ParameterModel parameter);
}

描述Controller类型属性的PropertyModel类型的最终目的是为了能够采用模型绑定的方式来完整针对对应属性的绑定,这与针对Action方法参数的绑定是一致的,所以PropertyModel和描述Action方法参数的ParameterModel类型具有相同的基类ParameterModelBase。为了定制Controller类型属性和Action方法参数类型的应用模型节点,MVC框架为我们定义了如下这个IParameterModelBaseConvention接口。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IParameterModelBaseConvention
{
    void Apply(ParameterModelBase parameter);
}

我们可以和上面一样将实现类型定义成标注到属性和参数上特性,也可以让实现类型同时也实现IApplicationModelConvention接口。值得一提的是,MVC框架并没有提供一个针对PropertyModel类型的IPropertyModelConvention接口,针对Action方法参数的IParameterModelConvention接口和IParameterModelBaseConvention接口之间也不存在继承关系。

六、ApplicationModelFactory

如下所示的是作为应用模型创建工厂的ApplicationModelFactory类型的定义。如代码片段所示,ApplicationModelFactory是一个内部类型。ApplicationModelFactory利用在构造函数中注入的参数得到所有注册的IApplicationModelProvider和IApplicationModelConvention对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
internal class ApplicationModelFactory
{
    private readonly IApplicationModelProvider[] 		_providers;
    private readonly IList<IApplicationModelConvention> 	_conventions;

    public ApplicationModelFactory(IEnumerable<IApplicationModelProvider> providers, IOptions<MvcOptions> options)
    {
        _providers 	= providers.OrderBy(it => it.Order).ToArray();
        _conventions 	= options.Value.Conventions;
    }

    public ApplicationModel CreateApplicationModel(IEnumerable<TypeInfo> controllerTypes)
    {
        var context = new ApplicationModelProviderContext(controllerTypes);
        for (var index = 0; index < _providers.Length; index++)
        {
            _providers[index].OnProvidersExecuting(context);
        }
        for (int index = _providers.Length - 1; index >= 0; index--)
        {
            _providers[index].OnProvidersExecuted(context);
        }
        ApplicationModelConventions.ApplyConventions(context.Result, _conventions);
        return context.Result;
    }
}

ApplicationModelFactory针对应用模型的构建体现在它的CreateApplicationModel方法上。如上面的代码片段所示,ApplicationModelFactory对象先根据提供的Controller类型列表创建出一个ApplicationModelProviderContext上下文对象。接下来,ApplicationModelFactory将这个上下文作为参数,按照Order属性确定的顺序调用每个IApplicationModelProvider对象的OnProvidersExecuting方法,然后再逆序调用它们的OnProvidersExecuted方法。ApplicationModelFactory最后会将通过所有IApplicationModelProvider对象参与构建的ApplicationModel从ApplicationModelProviderContext上下文中提取出来,并将各种方式注册的约定应用在该对象上,具体的实现体现在如下这个ApplyConventions方法上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
internal static class ApplicationModelConventions
{
    public static void ApplyConventions(ApplicationModel applicationModel, IEnumerable<IApplicationModelConvention> conventions)
    {
        foreach (var convention in conventions)
        {
            convention.Apply(applicationModel);
        }

        var controllers = applicationModel.Controllers.ToArray();
        foreach (var controller in controllers)
        {
            var controllerConventions = controller.Attributes.OfType<IControllerModelConvention>().ToArray();

            foreach (var controllerConvention in controllerConventions)
            {
                controllerConvention.Apply(controller);
            }

            var actions = controller.Actions.ToArray();
            foreach (var action in actions)
            {
                var actionConventions = action.Attributes.OfType<IActionModelConvention>().ToArray();

                foreach (var actionConvention in actionConventions)
                {
                    actionConvention.Apply(action);
                }

                var parameters = action.Parameters.ToArray();
                foreach (var parameter in parameters)
                {
                    var parameterConventions = parameter.Attributes.OfType<IParameterModelConvention>().ToArray();

                    foreach (var parameterConvention in parameterConventions)
                    {
                        parameterConvention.Apply(parameter);
                    }

                    var parameterBaseConventions = GetConventions<IParameterModelBaseConvention>(conventions, parameter.Attributes);
                    foreach (var parameterConvention in parameterBaseConventions)
                    {
                        parameterConvention.Apply(parameter);
                    }
                }
            }

            var properties = controller.ControllerProperties.ToArray();
            foreach (var property in properties)
            {
                var parameterBaseConventions = GetConventions<IParameterModelBaseConvention>(conventions, property.Attributes);

                foreach (var parameterConvention in parameterBaseConventions)
                {
                    parameterConvention.Apply(property);
                }
            }
        }
    }

    private static IEnumerable<TConvention> GetConventions<TConvention>(IEnumerable<IApplicationModelConvention> conventions, IReadOnlyList<object> attributes)
    {
        return Enumerable.Concat(conventions.OfType<TConvention>(), attributes.OfType<TConvention>());
    }
}

如上面的代码片段所示,注册在MvcOptions配置选项上的IApplicationModelConvention对象提供的约定会直接应用到ApplicationModel对象上。除此之外,Controller类型、Action方法和方法参数上标注的相应约定特性会被提取出来,它们承载的约定规则会分别应用到对应的ControllerModel、ActionModel和ParameterModel对象上。

对于表示Action方法参数的ParameterModel对象和表示Controller类型属性的ProperrtyModel对象来说,应用在对应参数和属性上实现了IParameterModelBaseConvention接口的特性,以及同时实现了IParameterModelBaseConvention接口的IApplicationModelConvention对象,会被提取出来并将它们承载的约定应用到对应的参数或者属性节点上。

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

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

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

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

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Excel催化剂开源第48波-Excel与PowerBIDeskTop互通互联之第二篇
此篇对应功能实现出自:第5波-使用DAX查询从PowerbiDeskTop中获取数据源https://www.jianshu.com/p/21b2ca8fd2b8
Excel催化剂
2021/08/19
9530
Excel催化剂功能第6波-导出PowerbiDesktop模型数据字典
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。 简书原文地址:https://www.jianshu.com/p/21b2ca8fd2b8
Excel催化剂
2021/08/19
6400
Excel催化剂功能第3波-与PowerbiDesktop互通互联-功能体验国际领先水平
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。 简书原文地址:https://www.jianshu.com/p/e05460ad407d
Excel催化剂
2021/08/19
8730
[PBI催化剂]国际水准,中国首款重量级PowerBIDeskTop外部工具问世
SQLBI的工具,有兴趣的可了解下,需要点英文阅读能力:https://www.sqlbi.com/tools/analyze-in-excel-for-power-bi-desktop/
Excel催化剂
2021/08/18
3.2K0
Excel催化剂功能第9波-数据透视表自动设置
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。
Excel催化剂
2021/08/19
2.5K0
全球首发,PBI催化剂更新,PowerBI参数字段表再爱多一点,批量创建,纯界面零代码,Excel数据源一键生成。
除此之外,另增加批量创建表关系功能,对同类事实表追加关系变得SoEasyShu,又是批量完成,爽到爆。
Excel催化剂
2023/04/26
2.2K0
全球首发,PBI催化剂更新,PowerBI参数字段表再爱多一点,批量创建,纯界面零代码,Excel数据源一键生成。
王者回归,PBI催化剂2.0发布,回归初心,个人永久性免费使用全部功能
PBI催化剂是笔者两年前开发的国内首款PowerBI外部工具,用于在PowerBI模型和报表层的元数据批量管理。
Excel催化剂
2022/09/02
4.9K0
王者回归,PBI催化剂2.0发布,回归初心,个人永久性免费使用全部功能
[PowerBI]中国首款重量级PowerBIDeskTop外部工具问世
过往的PowerBIDeskTop,它是一个独立的软件,不像Excel那样可以有二次开发的接口,但7月份更新PowerBIDeskTop后,已经开放了外部工具,单独有一个外部工具的选项卡。
Excel催化剂
2021/08/18
4.2K0
『持续进化』增加DAX查询更新功能,Excel催化剂与PowerBI联合接近大结局
虽然Excel的PowerPivot没有计算表功能,可能某些DAX新函数也不支持,但这并不妨碍它的强大。
Excel催化剂
2023/04/26
1.8K0
『持续进化』增加DAX查询更新功能,Excel催化剂与PowerBI联合接近大结局
Excel催化剂功能第7波-智能选区功能
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。 简书原文地址:https://www.jianshu.com/p/21b2ca8fd2b8
Excel催化剂
2021/08/19
7120
Excel催化剂功能第10波-快速排列工作表图形对象
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。
Excel催化剂
2021/08/19
1.5K0
Excel催化剂功能第8波-快速可视化数据
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。 简书原文地址: https://www.jianshu.com/p/ce7cca2baf89
Excel催化剂
2021/08/19
7780
个人永久性免费-Excel催化剂功能第32波-行列批量插入和删除
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。
Excel催化剂
2021/08/19
2.2K0
Excel催化剂开源第47波-Excel与PowerBIDeskTop互通互联之第一篇
此篇对应功能实现出自:第3波-与PowerbiDesktop互通互联(Excel透视表连接PowerbiDesktop数据模型)https://www.jianshu.com/p/e05460ad407d
Excel催化剂
2021/08/19
6460
Excel催化剂开源第49波-Excel与PowerBIDeskTop互通互联之第三篇
在PowerBIDeskTop开启的SSAS服务,和Sqlserver所开启的一个本质的区别是,前者其端口号是随机生成的,即上一次打开获得的端口号,下一次关闭后再打开,系统分配给它新的端口号,而后者因为是服务器版的,服务器的SSAS端口号是固定的,且服务器一般都是长期打开的,不存在端口号变化引起数据连接字符串要变更的情况。
Excel催化剂
2021/08/19
4550
个人永久性免费-Excel催化剂功能第37波-把Sqlserver的强大分析函数拿到Excel中用
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。
Excel催化剂
2021/08/19
1.9K0
个人永久性免费-Excel催化剂功能第33波-报表形式数据结构转标准数据源
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。
Excel催化剂
2021/08/19
1.6K0
李伟坚(Excel催化剂):接入AI人工智能NLP自然语言处理
原文在简书上发表,再同步到Excel催化剂微信公众号或其他平台上,文章后续有修改和更新将在简书上操作, 其他平台不作同步修改更新,因此建议阅读其他出处的文章时,尽可能跳转回简书平台上查看。
寒树Office与RPA
2019/11/29
1.8K0
一文带你全面认识Excel催化剂系列功能
因插件功能大部分是本人过去在工作中曾经开发过或曾经构想过在工作场景中有较大的使用率,同时也是其他主流插件未提供或提供的功能使用上略有欠缺的。
心莱科技雪雁
2019/04/22
1.5K0
惊喜,用Excel催化剂PBI功能,也能发起MDX查询​
在Excel里,除了可以使用透视表来访问数据模型,还可以用发起查询的方式来访问模型,返回一个二维表。
Excel催化剂
2022/03/30
2.2K0
惊喜,用Excel催化剂PBI功能,也能发起MDX查询​
推荐阅读
Excel催化剂开源第48波-Excel与PowerBIDeskTop互通互联之第二篇
9530
Excel催化剂功能第6波-导出PowerbiDesktop模型数据字典
6400
Excel催化剂功能第3波-与PowerbiDesktop互通互联-功能体验国际领先水平
8730
[PBI催化剂]国际水准,中国首款重量级PowerBIDeskTop外部工具问世
3.2K0
Excel催化剂功能第9波-数据透视表自动设置
2.5K0
全球首发,PBI催化剂更新,PowerBI参数字段表再爱多一点,批量创建,纯界面零代码,Excel数据源一键生成。
2.2K0
王者回归,PBI催化剂2.0发布,回归初心,个人永久性免费使用全部功能
4.9K0
[PowerBI]中国首款重量级PowerBIDeskTop外部工具问世
4.2K0
『持续进化』增加DAX查询更新功能,Excel催化剂与PowerBI联合接近大结局
1.8K0
Excel催化剂功能第7波-智能选区功能
7120
Excel催化剂功能第10波-快速排列工作表图形对象
1.5K0
Excel催化剂功能第8波-快速可视化数据
7780
个人永久性免费-Excel催化剂功能第32波-行列批量插入和删除
2.2K0
Excel催化剂开源第47波-Excel与PowerBIDeskTop互通互联之第一篇
6460
Excel催化剂开源第49波-Excel与PowerBIDeskTop互通互联之第三篇
4550
个人永久性免费-Excel催化剂功能第37波-把Sqlserver的强大分析函数拿到Excel中用
1.9K0
个人永久性免费-Excel催化剂功能第33波-报表形式数据结构转标准数据源
1.6K0
李伟坚(Excel催化剂):接入AI人工智能NLP自然语言处理
1.8K0
一文带你全面认识Excel催化剂系列功能
1.5K0
惊喜,用Excel催化剂PBI功能,也能发起MDX查询​
2.2K0
相关推荐
Excel催化剂开源第48波-Excel与PowerBIDeskTop互通互联之第二篇
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验