问题
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);
}
回答1:
Doing PUT or POST works for me when I change the method signature to accept a HttpRequestMessage request instead of T itself.
来源:https://stackoverflow.com/questions/6398134/wcf-webapis-self-hosting-not-accepting-put-verbs