禁用控制器结果的包装

Disable Wrapping of Controller Results

我目前使用的是 Abp.AspNetCore 的 v3.2.5。

我正在尝试将 Microsoft.AspNetCore.OData 的 Alpha 包集成到目前看起来还不错的项目中。

然而,当我尝试查询元数据控制器时 http://localhost:51078/odata/v1/$metadata 结果被包装了。 现在这也是 ODataController 的问题,但我可以简单地添加 [DontWrapResult] 属性。

我没有直接访问 MetadataController 的权限,所以我无法添加该属性。无论如何要禁用 Abp 项目的包装?

谢谢

编辑

这是当前的 ConfigureServices 方法

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .AddJsonOptions(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; });

    services
        .AddAuthentication()
        .AddCsDeviceAuth(options => { });

    services
        .AddOData();

    //Configure Abp and Dependency Injection
    var provider = services.AddAbp<PortalWebODataModule>(options =>
    {
        //Configure Log4Net logging
        options.IocManager.IocContainer.AddFacility<LoggingFacility>(
            f => f.LogUsing<Log4NetLoggerFactory>().WithConfig("log4net.config")
        );
    });

    services.Configure<MvcOptions>(options =>
    {
        var abpResultFilter = options.Filters.First(f => f is AbpResultFilter);
        options.Filters.Remove(abpResultFilter);
        options.Filters.AddService(typeof(ODataResultFilter));
    });

    return provider;
}

您可以实施 IResultFilter 并将 WrapOnSuccess 设置为 false:

public class ResultFilter : IResultFilter, ITransientDependency
{
    private readonly IAbpAspNetCoreConfiguration _configuration;

    public ResultFilter(IAbpAspNetCoreConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.HttpContext.Request.Path.Value.Contains("odata"))
        {
            var methodInfo = context.ActionDescriptor.GetMethodInfo();

            var wrapResultAttribute =
                GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(
                    methodInfo,
                    _configuration.DefaultWrapResultAttribute
                );

            wrapResultAttribute.WrapOnSuccess = false;
        }
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // No action
    }

    private TAttribute GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = default(TAttribute), bool inherit = true)
        where TAttribute : class
    {
        return memberInfo.GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
               ?? memberInfo.DeclaringType?.GetTypeInfo().GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
               ?? defaultValue;
    }
}

然后,在Startupclass中,在ConfigureServices方法中添加过滤器:

services.AddMvc(options =>
{
    options.Filters.AddService(typeof(ResultFilter));
});

参考文献:

备选方案;完全禁用系统内的 WrapResult 行为(在核心模块注册时):

        var abpAspNetCoreConfiguration = Configuration.Modules.AbpAspNetCore();
          abpAspNetCoreConfiguration.DefaultWrapResultAttribute.WrapOnSuccess = false;
          abpAspNetCoreConfiguration.DefaultWrapResultAttribute.WrapOnError = false;
        abpAspNetCoreConfiguration
            .CreateControllersForAppServices(
                typeof(AccessApplicationModule).GetAssembly()
            );

WrapOnSuccess 和 WrapOnError 标志可以设置为假值。

ABP v6.5 及更高版本

实现IWrapResultFilter并将其添加到模块的PreInitialize方法中的WrapResultFilters

有关详细信息,请参阅

ABP v6.5 之前

...包括题中提到的ABP v3.2.5

子类 AbpResultFilter:

using Abp.AspNetCore.Configuration;
using Abp.AspNetCore.Mvc.Results;
using Abp.AspNetCore.Mvc.Results.Wrapping;
using Microsoft.AspNetCore.Mvc.Filters;
using System;

namespace AbpODataDemo.Web.Host.Filters
{
    public class ODataResultFilter : AbpResultFilter
    {
        public ODataResultFilter(IAbpAspNetCoreConfiguration configuration, IAbpActionResultWrapperFactory actionResultWrapperFactory)
            : base(configuration, actionResultWrapperFactory)
        {
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            if (context.HttpContext.Request.Path.Value.StartsWith("/odata", StringComparison.InvariantCultureIgnoreCase))
            {
                return;
            }

            base.OnResultExecuting(context);
        }
    }
}

StartupConfigureServices方法中将AbpResultFilter替换为:

services.PostConfigure<MvcOptions>(options =>
{
    var index = options.Filters.IndexOf(new ServiceFilterAttribute(typeof(AbpResultFilter)));
    if (index != -1)
    {
        options.Filters.RemoveAt(index);
        options.Filters.Insert(index, new ServiceFilterAttribute(typeof(ODataResultFilter)));
    }
});

参考:https://github.com/aspnetboilerplate/sample-odata/pull/16