C# Owin 自托管服务控制器读取方法参数对象的所有属性值

Posted

技术标签:

【中文标题】C# Owin 自托管服务控制器读取方法参数对象的所有属性值【英文标题】:C# Owin self hosted service controller reads all property values of the method argument objects 【发布时间】:2021-03-06 09:30:21 【问题描述】:

我正在尝试用 Owin 自托管的 Asp.Net Rest WebApi 服务替换随我的应用程序发布的 WCF 服务。

我认为仅对 DataMember 属性进行了序列化/反序列化,但它似乎对并非如此的属性做了一些事情。

我将大致解释一下问题的背景是什么:

服务器应用程序是一个控制台应用程序,可以作为服务运行。 每个 WCF 服务及其方法都将被具有相同方法的 Web Api 控制器替换 在一段时间内,应用程序将发布两个服务端点(WCF 和 WebApi),以允许客户端使用他们选择的协议进行连接 每个 WCF/WebApi 方法只有一个参数由某个类型的对象表示(包含所有需要的参数作为属性),并且响应始终是另一种特定类型的对象(包含结果信息作为类属性)。 用作请求参数或响应结果的每个类都用适当的DataContractDataMember 属性修饰 WebApi 版本使用默认的序列化/反序列化 (Json)

例如,WCF 服务接口是这样的:

[ServiceContract]
public interface ISessionService

    [OperationContract]
    LoginResult Login(LoginRequest request);

WebApi 版本控制器是这样的:

[RoutePrefix(nameof(ISessionService))]
public class SessionServiceController : ApiController

    [HttpPost]
    [Route(nameof(ISessionService.Login))]
    public IHttpActionResult Login([FromBody] LoginRequest request)
    
        return this.Ok(this.LoginExecute(request));
    

LoginExecute 方法并不重要,它只返回一个 LoginResult 类的实例,仅用于运行服务方法逻辑。

我在反序列化服务参数时遇到了麻烦,因为似乎用作参数的对象的所有属性都被 Owin 管道中的某些东西读取了。 我不会深入解释为什么这会导致问题,但我可以简单地说,在某些情况下,各个类之间存在循环引用。 这会在读取对象实例的所有属性时导致无限循环,应该避免。 我注意到这个问题暂停了应用程序的执行,并看到调用的堆栈跟踪正在执行DelegatingHandler.SendAsync 方法。从这里开始按F10一步步调试,看到读取了很多属性getter。

我知道,要解决这个问题,我应该避免循环引用,但目前这是我负担不起的任务。

所以我要问:是否有一种解决方法可以防止 Web Api 反序列化像 WCF 对 DataContractSerializer 那样读取反序列化参数对象的所有属性?

编辑 24/11/2020 14:18

经过多次搜索,我发现导致读取模型所有属性的原因:IBodyModelValidator 服务。 我找到了一个适合我的解决方案,我将为遇到此“问题”的任何人回答自己

【问题讨论】:

ASP.NET Web API 使用 Json.Net 作为默认格式程序,因此如果您的应用程序仅使用 JSON 作为数据格式,您可以使用 [JsonIgnore] 忽略该属性。这个有类似的问题,可以参考:***.com/questions/11851207/… @DingPeng:Json.Net 支持 DataContract 和 DataMember 属性,我在参数和结果类中使用,我刚刚发现序列化不是这里的问题,但验证是。我将用我找到的解决方案自动回答我的问题,以防其他人感兴趣。谢谢 【参考方案1】:

经过一番研究,我发现问题不是序列化,而是IBodyModelValidator服务,它正在读取模型的所有属性元数据,包括属性值。

我找到的解决方案是覆盖HttpConfiguration.Services中的BodyModelValidator服务。

这个类有一个名为 bool ShouldValidateType(Type type) 的方法,它可以避免对类型进行验证,而且由于我没有在模型上使用任何集成验证,我可以从中跳过整个类型。

我使用自定义属性来确定类是否必须执行验证

步骤如下:

创建 WebApiOptionsAttribute 类

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public sealed class WebApiOptionsAttribute : Attribute


    public bool IsBodyModelValidatorDisabled  get; set;  = false;

    public static bool GetIsBodyModelValidatorDisabled(Type type)
    
        return type.GetCustomAttributes(typeof(WebApiOptionsAttribute), true).FirstOrDefault() is WebApiOptionsAttribute attribute ? attribute.IsBodyModelValidatorDisabled : false;
    


您可以将属性应用于任何类以控制是否应避免验证

创建一个 WebApiOptionsBodyModelValidator 类

public class WebApiOptionsBodyModelValidator : DefaultBodyModelValidator


    public override bool ShouldValidateType(Type type)
    
        if (WebApiOptionsAttribute.GetIsBodyModelValidatorDisabled(type))
        
            return false;
        
        else
        
            return true;
        
    

覆盖默认的 IBodyModelValidator 服务

在 Asp.Net 的 Global.asax 中:

protected void Application_Start(object sender, EventArgs e)

    GlobalConfiguration.Configure(Register);


public static void Register(HttpConfiguration config)

    config.Services.Replace(typeof(IBodyModelValidator), new WebApiOptionsBodyModelValidator());

或在自托管应用程序的 Owin 启动中:

public void StartWebApi()

    this.WebService = WebApp.Start(new StartOptions(), Configuration);


private static void Configuration(IAppBuilder appBuilder)

    // Configure Web API for self-host.
    var config = new HttpConfiguration();
    config.Services.Replace(typeof(IBodyModelValidator), new NSBodyModelValidator());
    appBuilder.UseWebApi(config);

使用属性来装饰类

[WebApiOptions(IsBodyModelValidatorDisabled = true)]
public class LoginRequest

    public bool Test
    
        get
        
            //if you place a breakpoint here, it should never hit
            //if you set IsBodyModelValidatorDisabled = false, the breakpoint should hit
            return true;
        
    

【讨论】:

以上是关于C# Owin 自托管服务控制器读取方法参数对象的所有属性值的主要内容,如果未能解决你的问题,请参考以下文章

在使用 Owin 自托管的 Web API 中获取远程主机 IP

在 DELETE 上不允许使用 Owin 自托管 Web API 405 方法

OWIN 自托管静态网站

具有 OWIN 自托管的 Web API 无类型 OData 服务返回 406 Not Acceptable

OWIN 自主机中等效的会话变量

[翻译]自托管WebApi使用OWIN和Unity