WCF WebApi 的自托管不接受 PUT 动词

发布于 2024-11-15 20:41:28 字数 3514 浏览 3 评论 0原文

我使用使用 PUT 动词的 WCF WebAPI 组合了一个 HTTP 驱动的 API。当托管在 IIS Express 上托管的 MVC3 项目内部时,一切都会按设计运行。

然而,当我进行单元测试时,我偶尔想要测试传输方面,而不仅仅是针对我自己的资源。我的单元测试因 405 - MethodNotAllowed 失败。同样,在 IIS 中托管的完全相同的服务也可以工作(我在配置文件中启用了 PUT 和 DELETE 动词)。

我怎样才能让我的测试中使用的“自托管”服务也接受这些动词?

几乎相同的“get”测试有效,所以我不期望这个概念以下是错误的..希望...

[Test]
public void PutNewMachine()
{
    // Create new record to add
    var machine = new Machine
                      {
                          ID = 1,
                          Name = "One",
                          Description = "Machine #1",
                          Location = 1
                      };

    using (var client = new HttpClient())
    {
        using (var request = new HttpRequestMessage(
                                         HttpMethod.Put, 
                                         HOST + "/1"))
        {
            request.Content = new ObjectContent<Machine>(machine);

            using (var response = client.Send(request))
            {
                Assert.AreEqual(
                    HttpStatusCode.Created,
                    response.StatusCode,
                    "New record put should have been acknowledged "
                                    + "with a status code of 'Created'");
            }
        }
    }
}

在测试设置中,我正在使用以下 Autofac 代码准备端点(这同样适用于“获取”):

var builder = new ContainerBuilder();
builder
    .Register(c => new FakeDatabase())
    .As<IDatabase>()
    .SingleInstance();
builder
    .Register(c => new GenericRepository<Machine>(c.Resolve<IDatabase>()))
    .As<IResourceRepository<Machine>>();
builder
    .Register(c => new MachineService(c.Resolve<IResourceRepository<Machine>>()))
    .As<MachineService>();
Container = builder.Build();
Scope = Container.BeginLifetimeScope();

host = new HttpServiceHost(typeof(MachineService), HOST);
host.AddDependencyInjectionBehavior<MachineService>(Container);
host.Open();

我的服务定义如下接口:

[ServiceContract]
public interface IResourceService<in TKey, TResource>
{
    [WebGet(UriTemplate = "{key}")]
    TResource Get(TKey key);

    [WebInvoke(Method = "PUT", UriTemplate = "{key}")]
    TResource Put(TKey key, TResource resource);

    [WebInvoke(Method = "POST")]
    TResource Post(TResource resource);

    [WebInvoke(Method = "DELETE", UriTemplate = "{key}")]
    void Delete(TKey key);
}

例如,如果我有一个MachineService,它实现了接口(class MachineService : IResourceService... : IResourceService 都已试用 - Get = OK, Put = Nothing。

编辑:我似乎在 InternalServerError 和 MethodNotAllowed 错误之间徘徊 - 仅当使用自托管时我才确保。用户,有权打开端口(Win7 + 非管理员),但结果加上我选择的端口似乎可以预测“Post”功能似乎有类似的问题! :-(

EDIT2:界面现已更改为可用!

[ServiceContract]
public interface IResourceService<in TKey, TResource>
{
    [WebGet(UriTemplate = "{key}")]
    TResource Get(TKey key);

    [WebInvoke(Method = "PUT", UriTemplate = "{key}")]
    TResource Put(HttpRequestMessage<TResource> resourceRequest, TKey key);

    [WebInvoke(Method = "POST", UriTemplate = "{key}")]
    TResource Post(HttpRequestMessage<TResource> resourceRequest, TKey key);

    [WebInvoke(Method = "DELETE", UriTemplate = "{key}")]
    void Delete(TKey key);
}

I have put together a HTTP driven API using the WCF WebAPI that uses the PUT verb. When hosted inside of an MVC3 project that is hosted upon IIS Express, everything works as designed.

However, when I unit-test I'm occasionally wanting to test the transport aspects rather than just against my own resources. My unit-tests fail with a 405 - MethodNotAllowed. Again, exactly the same service hosted in IIS works (where I enabled the PUT and DELETE verbs in the configuration file).

How can I get the 'self-hosted' service, as used in my testing, to accept these verbs too?

The almost identical 'get' tests work, so I'm not expecting the concept of the following to be at fault.. hopefully...

[Test]
public void PutNewMachine()
{
    // Create new record to add
    var machine = new Machine
                      {
                          ID = 1,
                          Name = "One",
                          Description = "Machine #1",
                          Location = 1
                      };

    using (var client = new HttpClient())
    {
        using (var request = new HttpRequestMessage(
                                         HttpMethod.Put, 
                                         HOST + "/1"))
        {
            request.Content = new ObjectContent<Machine>(machine);

            using (var response = client.Send(request))
            {
                Assert.AreEqual(
                    HttpStatusCode.Created,
                    response.StatusCode,
                    "New record put should have been acknowledged "
                                    + "with a status code of 'Created'");
            }
        }
    }
}

In the setup to the test, I'm preparing the end-points using the following Autofac code (and again this works for the 'Get'):

var builder = new ContainerBuilder();
builder
    .Register(c => new FakeDatabase())
    .As<IDatabase>()
    .SingleInstance();
builder
    .Register(c => new GenericRepository<Machine>(c.Resolve<IDatabase>()))
    .As<IResourceRepository<Machine>>();
builder
    .Register(c => new MachineService(c.Resolve<IResourceRepository<Machine>>()))
    .As<MachineService>();
Container = builder.Build();
Scope = Container.BeginLifetimeScope();

host = new HttpServiceHost(typeof(MachineService), HOST);
host.AddDependencyInjectionBehavior<MachineService>(Container);
host.Open();

My service is defined in the following interface:

[ServiceContract]
public interface IResourceService<in TKey, TResource>
{
    [WebGet(UriTemplate = "{key}")]
    TResource Get(TKey key);

    [WebInvoke(Method = "PUT", UriTemplate = "{key}")]
    TResource Put(TKey key, TResource resource);

    [WebInvoke(Method = "POST")]
    TResource Post(TResource resource);

    [WebInvoke(Method = "DELETE", UriTemplate = "{key}")]
    void Delete(TKey key);
}

So, for example, if I have a MachineService, it implements the interface (both class MachineService : IResourceService<string, Machine> and ... : IResourceService<int, Machine> have been trialled - Get = OK, Put = Nothing.

EDIT: I seem to be bouncing between InternalServerError and MethodNotAllowed errors - only when using the self-hosting. I have ensured that I, as a user, have rights to open the port (Win7 + non-admin) but the results of that plus my choice of ports seems predicable functional for Get. "Post" seems to be having similar issues! :-(

EDIT2: Interface has now changed to which works!

[ServiceContract]
public interface IResourceService<in TKey, TResource>
{
    [WebGet(UriTemplate = "{key}")]
    TResource Get(TKey key);

    [WebInvoke(Method = "PUT", UriTemplate = "{key}")]
    TResource Put(HttpRequestMessage<TResource> resourceRequest, TKey key);

    [WebInvoke(Method = "POST", UriTemplate = "{key}")]
    TResource Post(HttpRequestMessage<TResource> resourceRequest, TKey key);

    [WebInvoke(Method = "DELETE", UriTemplate = "{key}")]
    void Delete(TKey key);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

顾北清歌寒 2024-11-22 20:41:28

当我更改方法签名以接受 HttpRequestMessage 请求而不是 T 本身时,执行 PUT 或 POST 对我有用。

Doing PUT or POST works for me when I change the method signature to accept a HttpRequestMessage request instead of T itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文