0

I am currently using v3.2.5 of Abp.AspNetCore.

I am trying to integrate an Alpha package of Microsoft.AspNetCore.OData into the project which is so far looking ok.

However when i try and query the metadata controller http://localhost:51078/odata/v1/$metadata the result is wrapped. Now this was an issue for the ODataControllers as well, but i could simply add the [DontWrapResult] attribute.

I dont have direct access to the MetadataController so i am unable to add the attribute. Is there anyway to disable wrapping for an Abp project?

Thanks

Edit

Here is the current ConfigureServices method

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;
}
tjackadams
  • 815
  • 2
  • 9
  • 26

3 Answers3

1

You can implement IResultFilter and set WrapOnSuccess to 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;
    }
}

Then, in Startup class, add the filter in ConfigureServices method:

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

References:

aaron
  • 39,695
  • 6
  • 46
  • 102
  • sorry about the delay but yes i can confirm this is working. Many Thanks! – tjackadams Dec 29 '17 at 17:37
  • 1
    this code will lead to bug, as if you first requested /odata/$metadata the DefaultWrapResultAttribute.WrapOnSuccess will set to false, till now this is what we want, but if you then requested /AbpUserConfiguration/GetAll it should be wrapped but it doesn't(as we set the prop to false). – Ramy Yousef Oct 26 '20 at 08:02
  • 1
    I've just encountered the exact bug mentionned by @KasperRoma. The scope of the change is much larger than the current request and thus it causes side-effects. Would not recommend. – Carl Quirion Feb 01 '22 at 19:54
  • Thanks for reporting the bug. I have posted an updated answer. – aaron Feb 02 '22 at 13:25
1

Alternative solution; to completely disable WrapResult behavior within the system ( at the Core module registration):

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

WrapOnSuccess and WrapOnError flags can be set to false values.

Oğuzhan Kahyaoğlu
  • 1,727
  • 2
  • 15
  • 20
0

ABP v6.5 and later

Implement IWrapResultFilter and add it to WrapResultFilters in the module's PreInitialize method.

See https://stackoverflow.com/questions/70947461/how-to-control-response-wrapping-in-abp-on-a-per-route-basis/70955045#70955045 for more details.

Before ABP v6.5

...including ABP v3.2.5 mentioned in the question.

Subclass 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);
        }
    }
}

Replace AbpResultFilter with it in the Startup ConfigureServices method:

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)));
    }
});

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

aaron
  • 39,695
  • 6
  • 46
  • 102