使用 HttpWebRequest 连接 Azure 服务总线中继(WCF 端点)
Connecting Azure Service Bus Relay (WCF endpoint) using HttpWebRequest
请帮助。我试图使用 HttpWebRequest 访问暴露给服务总线中继端点的 WCF 服务。
我通过 OAuth WRAP 协议从 ACS 成功获得了令牌。使用该令牌作为请求中的授权 header,我创建了一个 WebRequest 来与 WCF 服务通信,端点配置为 WebHttpRelayBinding 并且 WCF 服务方法应用了 OperationContractAttribute 和 WebGetAttribute。
当我 运行 客户端应用程序出现以下错误时:
The message with To
'https://namespace.servicebus.windows.net/Student/GetInfo/GetStudentInfo/1'
cannot be processed at the receiver, due to an AddressFilter mismatch
at the EndpointDispatcher. Check that the sender and receiver's
EndpointAddresses agree.
我用谷歌搜索并找到了将以下属性应用于服务的建议 class:
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
虽然这解决了之前的错误,但现在客户端应用程序以以下错误结束:
The message with Action 'GET' cannot be processed at the receiver, due
to a ContractFilter mismatch at the EndpointDispatcher. This may be
because of either a contract mismatch (mismatched Actions between
sender and receiver) or a binding/security mismatch between the sender
and the receiver. Check that sender and receiver have the same
contract and the same binding (including security requirements, e.g.
Message, Transport, None).
我想我在 WCF 服务端遗漏了一些东西。共享客户端和服务代码供您查看。
WCF 服务代码:
[ServiceContract]
interface IStudentInfo
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "/GetStudentInfo/{studentId}")]
string GetStudentInfo(string studentId);
}
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
private class StudentInfo : IStudentInfo
{
string IStudentInfo.GetStudentInfo(string studentId)
{
string returnString = null;
// .....
return returnString;
}
}
public void Run()
{
Console.WriteLine("LISTENER");
Console.WriteLine("========");
string serviceNamespace = "namespace";
string issuerName = "owner";
string issuerKey = "key";
string servicePath = "Student/GetInfo";
ServiceHost sh = new ServiceHost(typeof(StudentInfo));
// Binding
WebHttpRelayBinding binding2 = new WebHttpRelayBinding();
Uri uri = ServiceBusEnvironment.CreateServiceUri(Uri.UriSchemeHttps, serviceNamespace, servicePath);
Console.WriteLine("Service Uri: " + uri);
Console.WriteLine();
sh.AddServiceEndpoint(typeof(IStudentInfo), binding2, uri);
// Create the ServiceRegistrySettings behavior for the endpoint.
var serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);
// Create the shared secret credentials object for the endpoint matching the
// Azure access control services issuer
var sharedSecretServiceBusCredential = new TransportClientEndpointBehavior()
{
TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerKey)
};
// Add the service bus credentials to all endpoints specified in configuration.
foreach (var endpoint in sh.Description.Endpoints)
{
endpoint.Behaviors.Add(serviceRegistrySettings);
endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
}
sh.Open();
Console.WriteLine("Press ENTER to close");
Console.ReadLine();
sh.Close();
}
服务消费代码:
static void Main(string[] args)
{
var studentId = "1";
string _token = GetToken();
Console.WriteLine(_token);
// Create and configure the Request
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://namespace.servicebus.windows.net/Student/GetInfo/GetStudentInfo/" + studentId);
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "GET";
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, string.Format("WRAP access_token=\"{0}\"", _token));
// Get the response using the Request
HttpWebResponse response = httpWebRequest.GetResponse() as HttpWebResponse;
// Read the stream from the response object
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
// Read the result from the stream reader
string result = reader.ReadToEnd();
Console.WriteLine("Result: " + result);
Console.ReadLine();
}
static string GetToken()
{
string base_address = string.Format("https://namespace-sb.accesscontrol.windows.net");
string wrap_name = "owner";
string wrap_password = "key";
string wrap_scope = "http://namespace.servicebus.windows.net/";
WebClient client = new WebClient();
client.BaseAddress = base_address;
NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", wrap_name);
values.Add("wrap_password", wrap_password);
values.Add("wrap_scope", wrap_scope);
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);
string response = Encoding.UTF8.GetString(responseBytes);
string token = response.Split('&')
.Single(value => value.StartsWith("wrap_access_token="))
.Split('=')[1];
string _token = HttpUtility.UrlDecode(token);
return _token;
}
终于搞定了!
我缺少将 WCF 服务公开为 REST 端点所必需的端点 WebHttpBehavior
。
endpoint.Behaviors.Add(new WebHttpBehavior());
或者我可以在 WebServiceHost
中托管服务而不是 `ServiceHost' 来启用 REST 绑定。
WebServiceHost sh = new WebServiceHost(typeof(StudentInfo));
请帮助。我试图使用 HttpWebRequest 访问暴露给服务总线中继端点的 WCF 服务。
我通过 OAuth WRAP 协议从 ACS 成功获得了令牌。使用该令牌作为请求中的授权 header,我创建了一个 WebRequest 来与 WCF 服务通信,端点配置为 WebHttpRelayBinding 并且 WCF 服务方法应用了 OperationContractAttribute 和 WebGetAttribute。
当我 运行 客户端应用程序出现以下错误时:
The message with To 'https://namespace.servicebus.windows.net/Student/GetInfo/GetStudentInfo/1' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.
我用谷歌搜索并找到了将以下属性应用于服务的建议 class:
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
虽然这解决了之前的错误,但现在客户端应用程序以以下错误结束:
The message with Action 'GET' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
我想我在 WCF 服务端遗漏了一些东西。共享客户端和服务代码供您查看。
WCF 服务代码:
[ServiceContract]
interface IStudentInfo
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "/GetStudentInfo/{studentId}")]
string GetStudentInfo(string studentId);
}
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
private class StudentInfo : IStudentInfo
{
string IStudentInfo.GetStudentInfo(string studentId)
{
string returnString = null;
// .....
return returnString;
}
}
public void Run()
{
Console.WriteLine("LISTENER");
Console.WriteLine("========");
string serviceNamespace = "namespace";
string issuerName = "owner";
string issuerKey = "key";
string servicePath = "Student/GetInfo";
ServiceHost sh = new ServiceHost(typeof(StudentInfo));
// Binding
WebHttpRelayBinding binding2 = new WebHttpRelayBinding();
Uri uri = ServiceBusEnvironment.CreateServiceUri(Uri.UriSchemeHttps, serviceNamespace, servicePath);
Console.WriteLine("Service Uri: " + uri);
Console.WriteLine();
sh.AddServiceEndpoint(typeof(IStudentInfo), binding2, uri);
// Create the ServiceRegistrySettings behavior for the endpoint.
var serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);
// Create the shared secret credentials object for the endpoint matching the
// Azure access control services issuer
var sharedSecretServiceBusCredential = new TransportClientEndpointBehavior()
{
TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerKey)
};
// Add the service bus credentials to all endpoints specified in configuration.
foreach (var endpoint in sh.Description.Endpoints)
{
endpoint.Behaviors.Add(serviceRegistrySettings);
endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
}
sh.Open();
Console.WriteLine("Press ENTER to close");
Console.ReadLine();
sh.Close();
}
服务消费代码:
static void Main(string[] args)
{
var studentId = "1";
string _token = GetToken();
Console.WriteLine(_token);
// Create and configure the Request
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://namespace.servicebus.windows.net/Student/GetInfo/GetStudentInfo/" + studentId);
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "GET";
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, string.Format("WRAP access_token=\"{0}\"", _token));
// Get the response using the Request
HttpWebResponse response = httpWebRequest.GetResponse() as HttpWebResponse;
// Read the stream from the response object
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
// Read the result from the stream reader
string result = reader.ReadToEnd();
Console.WriteLine("Result: " + result);
Console.ReadLine();
}
static string GetToken()
{
string base_address = string.Format("https://namespace-sb.accesscontrol.windows.net");
string wrap_name = "owner";
string wrap_password = "key";
string wrap_scope = "http://namespace.servicebus.windows.net/";
WebClient client = new WebClient();
client.BaseAddress = base_address;
NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", wrap_name);
values.Add("wrap_password", wrap_password);
values.Add("wrap_scope", wrap_scope);
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);
string response = Encoding.UTF8.GetString(responseBytes);
string token = response.Split('&')
.Single(value => value.StartsWith("wrap_access_token="))
.Split('=')[1];
string _token = HttpUtility.UrlDecode(token);
return _token;
}
终于搞定了!
我缺少将 WCF 服务公开为 REST 端点所必需的端点 WebHttpBehavior
。
endpoint.Behaviors.Add(new WebHttpBehavior());
或者我可以在 WebServiceHost
中托管服务而不是 `ServiceHost' 来启用 REST 绑定。
WebServiceHost sh = new WebServiceHost(typeof(StudentInfo));