ASP.NET Web API 操作方法参数的依赖注入

2023-12-20

我正在使用 C# 开发一个 ASP.NET Web API 项目,用于移动应用程序的 JSON 接口。我的想法是为所有请求创建接口,然后仅在 Web API 代码中使用这些接口。

我最终得到了这样的结果:

public interface IApiObject {}
public interface IApiResponse<T> : IApiObject where T : IApiObject {}
public interface IApiRegistrationRequest : IApiObject {}

我的控制器看起来像这样:

public class MyApiController : ApiController
{

    public IApiResponse<IApiObject> Register(IApiRegistrationRequest request) {
        // do some stuff
    }
}

我的 Web API 项目也包含这些接口的实现。

我假设 Web API 项目像 MVC 项目一样使用模型绑定,所以我创建了一个继承感知的 ModelBinderProvider http://www.matthidinger.com/archive/2011/08/16/An-inheritance-aware-ModelBinderProvider-in-MVC-3.aspx用于为所有 IApiObject 提供绑定器和使用 Unity 容器解析其实现的接口的自定义模型绑定器。

然而,经过更多调查后,我发现Web API如何进行参数绑定 http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx并发现 Web API 对于复杂类型使用格式化程序而不是模型绑定程序。链接的博客文章建议在我的操作参数上使用 ModelBinderAttribute,但该属性仅接受类型作为参数。然而,我的自定义模型绑定器不包含空构造函数(它需要一个统一容器),因此我需要传递它的一个实例。

我能想到的另一种方法是对格式化程序使用依赖注入。不幸的是,我对它们不熟悉,因为我以前从未使用过它们。

哪条路是正确的?我该怎么做?


这就是我现在想出的并且有效。

我决定创建一个自定义格式化程序,它执行统一调用并将所有进一步的操作转发到使用解析类型的另一个格式化程序。它看起来像很多代码,但这只是因为所有方法都需要被覆盖,以便始终可以解析类型。

public class UnityFormatter : MediaTypeFormatter
{
    private MediaTypeFormatter formatter;

    private IUnityContainer container;

    public UnityFormatter(MediaTypeFormatter formatter, IUnityContainer container)
    {
        this.formatter = formatter;
        this.container = container;

        foreach (var supportedMediaType in this.formatter.SupportedMediaTypes)
        {
            this.SupportedMediaTypes.Add(supportedMediaType);
        }

        foreach (var supportedEncoding in this.formatter.SupportedEncodings)
        {
            this.SupportedEncodings.Add(supportedEncoding);
        }

        foreach (var mediaTypeMapping in this.MediaTypeMappings)
        {
            this.MediaTypeMappings.Add(mediaTypeMapping);
        }

        this.RequiredMemberSelector = this.formatter.RequiredMemberSelector;
    }

    private Type ResolveType(Type type)
    {
        return this.container.Registrations.Where(n => n.RegisteredType == type).Select(n => n.MappedToType).FirstOrDefault() ?? type;
    }

    public override bool CanReadType(Type type)
    {
        return this.formatter.CanReadType(this.ResolveType(type));
    }

    public override bool CanWriteType(Type type)
    {
        return this.formatter.CanWriteType(this.ResolveType(type));
    }

    public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
    {
        return this.formatter.GetPerRequestFormatterInstance(this.ResolveType(type), request, mediaType);
    }

    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
    {
        return this.formatter.ReadFromStreamAsync(this.ResolveType(type), readStream, content, formatterLogger);
    }

    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
    {
        this.formatter.SetDefaultContentHeaders(this.ResolveType(type), headers, mediaType);
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
    {
        return this.formatter.WriteToStreamAsync(this.ResolveType(type), value, writeStream, content, transportContext);
    }
}

最后,在应用程序配置(Global.asax Application_Start)中注册我们的自定义格式化程序。我选择将所有当前格式化程序替换为我的自定义格式化程序的实例,因此我可以获得所有数据类型的反映。

// set up unity container, register all types
UnityContainer container = new UnityContainer();
container.RegisterType<IApiRegistrationRequest, ApiRegistrationRequest>();

// save existing formatters and remove them from the config
List<MediaTypeFormatter> formatters = new List<MediaTypeFormatter>(GlobalConfiguration.Configuration.Formatters);
GlobalConfiguration.Configuration.Formatters.Clear();

// create an instance of our custom formatter for each existing formatter
foreach (MediaTypeFormatter formatter in formatters)
{
    GlobalConfiguration.Configuration.Formatters.Add(new UnityFormatter(formatter, container));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ASP.NET Web API 操作方法参数的依赖注入 的相关文章

随机推荐

  • Solr suggest - 如何将 solr suggest 定义为不区分大小写

    我的建议 拼写检查器 返回区分大小写的答案 我用它来自动完成 狗和狗返回不同的短语 我的建议定义如下 在 solrconfig 中
  • 强制 jQuery Mobile 重新评估动态插入内容的样式/主题

    客观的 通过加载 HTML 内容 ajax 将其插入 DOM 让 jQuery Mobile 应用主题样式 Problem 内容已插入 但缺少 jQuery Mobile 主题 Code ajax success function html
  • 从 vb 确定 Url 是绝对的还是相对的 [重复]

    这个问题在这里已经有答案了 我试图在 vb 中确定 URL 是绝对的还是相对的 我确信必须有一些库可以做到这一点 但我不确定是哪个 基本上我需要能够分析字符串 例如 相对 路径 和或 http www absolutepath com su
  • Swift 3 iMessage 扩展无法打开 URL

    我正在创建一个 iOS 应用程序 iMessage 扩展 根据苹果的例子 https developer apple com library prerelease content samplecode IceCreamBuilder Int
  • Cypress - 检查文件是否已下载

    我在尝试检查文件是否已下载时遇到了一些问题 单击按钮生成 PDF 文件并开始下载 我需要检查它是否有效 赛普拉斯能做到吗 赛普拉斯 插件 index js const path require path const fs require f
  • 为什么我不能在抽象 C# 类上创建抽象构造函数?

    我正在创建一个抽象类 我希望我的每个派生类都被迫实现构造函数的特定签名 因此 如果我想强迫他们实现一种方法 我做了我会做的事情 我做了一个抽象的方法 public abstract class A abstract A int a int
  • Typescript 中带有 Observable 的 XMLHttpRequest

    当我尝试管理上传文件的 XMLHttpRequest 调用的结果时 我遇到了 tslint 问题 这是我目前在互联网上找到的方法 Files upload request makeFileRequest url string files A
  • 如何使用 CURLOPT_HEADERFUNCTION 读取单个响应标头字段?

    我正在实现一个 C 程序 它需要从读取远程文件的大小Content Length标题 当Content Length在响应标头中发送 我查看了 libcurl 的文档 到目前为止我能想到的最好的方法是回调函数CURLOPT HEADERFU
  • 在 Access VBA 中实施正则表达式以提高密码复杂性

    我目前正在开发一个需要密码验证的项目 因为最终用户可以更改其登录密码 但没有验证来确保给定的密码符合规定 这有点棘手 因为我对使用 VBA 和正则表达式相当陌生 而且我找不到我正在寻找的答案 该项目有一个 Access 2010 前端 虽然
  • 如何在 MySQL 中强制复合唯一性?

    我遇到了一种情况 我想确保表的复合元素是唯一的 例如 Table id char 36 primary key fieldA varChar 12 not null fieldB varChar 36 not null 我不希望 field
  • CentOS安装mod_dav_svn

    我正在尝试在 centos 5 VPS 上安装 subversion 我设法安装了 subversion 但是当我尝试这样做时yum install mod dav svn我收到此错误 错误 缺少依赖项 httpd mmn 包裹需要2005
  • 如何从 zlib 确定 gzip 数据的压缩大小?

    我正在使用 zlib 执行 gzip 压缩 zlib 将数据压缩后直接写入打开的 TCP 套接字 socket fd is a file descriptor for an open TCP socket gzFile gzf gzdope
  • Rust 中精确的内存布局控制?

    据我所知 Rust 编译器可以对结构的每个字段进行打包 重新排序和添加填充 如果需要的话 如何指定精确的内存布局 在 C 中 我有StructLayout属性 并且在 C C 中 我可以使用各种编译器扩展 我可以通过检查预期值位置的字节偏移
  • Android NDK 包括使用 Gradle 和 CMake 的第 3 方预构建共享库

    我正在努力将预构建的共享库包含在我的 android 项目中 有问题的库是 libusb 我的 android 项目的 NDK 部分需要它 一切都编译和链接正常 即项目正在成功构建 但是在我的设备上安装 apk 时 应用程序崩溃了 来自监视
  • 如果端口已使用,spring-boot 自动更改端口

    我正在使用 Windows 命令来运行带有 embedded tomcat 的 spring boot 应用程序 此外 我需要使用 CommandlineRunner 运行许多控制台应用程序 我正面临端口使用问题 APPLICATION F
  • FlowType:类型的继承(类型A是类型B的子集...)

    自发布以来流动 42 https github com facebook flow releases tag v0 42 0 你可以 使用对象类型传播 type TypeB TypeA 我想这确实是关于 FlowType 的初学者类型的问题
  • 在没有 XML 的情况下配置 JPA/Hibernate/PostgreSQL

    我又回到了 Java 世界 并尝试使用 JPA Hibernate 和 PostgreSQL 配置一个新的 Spring Web 应用程序 我发现了很多带有各种 XML 配置文件的旧示例 我想知道是否有一种首选的新方法可以在不依赖 XML
  • 如何使用js自动下载PDF?

    我的场景是 PDF 文件自动下载 然后用户填写它 当单击 PDF 中的提交按钮时 它会连接到 java servlet 并将其保存在数据库中 用户点击按钮 JavaScript 代码自动运行并下载 PDF 文件 自动使用 JavaScrip
  • 覆盖 Swagger 排序

    我想按相反的字母顺序组织我的 swagger api 但它默认为按字母顺序 有没有一种简单的方法可以做到这一点 具体使用 Swashbuckle Core 5 2 1 您可以为这两个操作的 UI 创建一个排序器 operationsSort
  • ASP.NET Web API 操作方法参数的依赖注入

    我正在使用 C 开发一个 ASP NET Web API 项目 用于移动应用程序的 JSON 接口 我的想法是为所有请求创建接口 然后仅在 Web API 代码中使用这些接口 我最终得到了这样的结果 public interface IAp