HttpOperationHandlerFactory 和 InputParameters 问题
我为我的 WCF WebAPI 项目编写了一个自定义操作处理程序,如下所示:
public class AuthenticationOperationHandler : HttpOperationHandlerFactory
{
protected override Collection<HttpOperationHandler> OnCreateRequestHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation)
{
var baseHandlers = base.OnCreateRequestHandlers(endpoint, operation);
if (operation.InputParameters.Where(p => p.Name.ToLower() == "username").Any() &&
operation.InputParameters.Where(p => p.Name.ToLower() == "password").Any())
{
baseHandlers.Add(new AuthenticateRequestHandler(string.Format("{0}:{1}", operation.InputParameters.Where(p => p.Name == "username").First ().Name, operation.InputParameters.Where(p => p.Name == "password").First().Name)));
}
else
{
throw new WebFaultException(HttpStatusCode.Forbidden);
}
return baseHandlers;
}
}
以及添加到管道中的这个自定义 RequestHandler:
public class AuthenticateRequestHandler : HttpOperationHandler<HttpRequestMessage, string>
{
public AuthenticateRequestHandler(string outputParameterName)
: base(outputParameterName)
{
}
public override string OnHandle(HttpRequestMessage input)
{
var stringValue = input.Content.ReadAsString();
var username = stringValue.Split(':')[0];
var password = stringValue.Split(':')[1];
var isAuthenticated = ((BocaMembershipProvider)Membership.Provider).ValidateUser(username, password);
if (!isAuthenticated)
{
throw new WebFaultException(HttpStatusCode.Forbidden);
}
return stringValue;
}
}
这是我的 API 实现:
[ServiceContract]
public class CompanyService
{
[WebInvoke(UriTemplate = "", Method = "POST")]
public bool Post(string username, string password)
{
return true;
}
}
我在 Global.asax 文件中的配置是
public static void RegisterRoutes(RouteCollection routes)
{
var config = HttpHostConfiguration.Create().SetOperationHandlerFactory(new AuthenticationOperationHandler());
routes.MapServiceRoute<AuthenticationService>("login", config);
routes.MapServiceRoute<CompanyService>("companies", config);
}
当尝试发送 POST 请求时到 /companys 我收到以下错误消息:
HttpOperationHandlerFactory 无法确定输入 与请求消息内容关联的参数 用于服务操作“Post”。如果操作不需要内容 在请求消息中使用 HTTP GET 方法进行操作。 否则,请确保一个输入参数具有它的 IsContentParameter 属性设置为“True”或者是以下类型 可分配给以下内容之一:HttpContent、ObjectContent
1、 HttpRequestMessage 或 HttpRequestMessage
1.
这条线上:
var baseHandlers = base.OnCreateRequestHandlers(endpoint, operation);
知道为什么会发生这种情况以及如何解决这个问题,以便强制用户在每个请求中发送用户名/密码参数,然后根据会员 API 进行验证吗?
I've written a custom OperationHandler for my WCF WebAPI project as follows:
public class AuthenticationOperationHandler : HttpOperationHandlerFactory
{
protected override Collection<HttpOperationHandler> OnCreateRequestHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation)
{
var baseHandlers = base.OnCreateRequestHandlers(endpoint, operation);
if (operation.InputParameters.Where(p => p.Name.ToLower() == "username").Any() &&
operation.InputParameters.Where(p => p.Name.ToLower() == "password").Any())
{
baseHandlers.Add(new AuthenticateRequestHandler(string.Format("{0}:{1}", operation.InputParameters.Where(p => p.Name == "username").First ().Name, operation.InputParameters.Where(p => p.Name == "password").First().Name)));
}
else
{
throw new WebFaultException(HttpStatusCode.Forbidden);
}
return baseHandlers;
}
}
As well as this custom RequestHandler which is added to the pipeline:
public class AuthenticateRequestHandler : HttpOperationHandler<HttpRequestMessage, string>
{
public AuthenticateRequestHandler(string outputParameterName)
: base(outputParameterName)
{
}
public override string OnHandle(HttpRequestMessage input)
{
var stringValue = input.Content.ReadAsString();
var username = stringValue.Split(':')[0];
var password = stringValue.Split(':')[1];
var isAuthenticated = ((BocaMembershipProvider)Membership.Provider).ValidateUser(username, password);
if (!isAuthenticated)
{
throw new WebFaultException(HttpStatusCode.Forbidden);
}
return stringValue;
}
}
and this is my API Implementation:
[ServiceContract]
public class CompanyService
{
[WebInvoke(UriTemplate = "", Method = "POST")]
public bool Post(string username, string password)
{
return true;
}
}
My configuration in Global.asax file is
public static void RegisterRoutes(RouteCollection routes)
{
var config = HttpHostConfiguration.Create().SetOperationHandlerFactory(new AuthenticationOperationHandler());
routes.MapServiceRoute<AuthenticationService>("login", config);
routes.MapServiceRoute<CompanyService>("companies", config);
}
When trying to send a POST request to /companies I receive the following error message:
The HttpOperationHandlerFactory is unable to determine the input
parameter that should be associated with the request message content
for service operation 'Post'. If the operation does not expect content
in the request message use the HTTP GET method with the operation.
Otherwise, ensure that one input parameter either has it's
IsContentParameter property set to 'True' or is a type that is
assignable to one of the following: HttpContent, ObjectContent1,
1.
HttpRequestMessage or HttpRequestMessage
on this line:
var baseHandlers = base.OnCreateRequestHandlers(endpoint, operation);
Any idea why this happens and how to fix this in order to force user send username/password parameters in each and every request and validate it against the Membership API afterwards?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为了回答您的问题,您的 UriTemplate 属性为空,这就是引发异常的原因。它应该设置如下:
您的代码中仍然存在错误,因为两个输入参数都接收相同的字符串,即 username=JohnDoe:password=qwerty
要解决您的问题,这是一个很好的 文章介绍如何使用 WCF Web API 实现 HTTP 基本身份验证。
To answer your question, your UriTemplate property is empty, which is why an exception is thrown. It should be set as follows:
There's still a bug in your code because both input parameters receive the same string, namely username=JohnDoe:password=qwerty
To solve your problem, this is a good article on how to implement HTTP basic authentication with WCF Web API.