WCF: получение MethodInfo из OperationContext
Есть ли элегантный способ получить метод, который будет выполняться на экземпляре службы, из MessageInspector/AuthorizationPolicy/ какой-либо другой точки расширения? Я мог бы использовать
OperationContext.Current.IncomingMessageHeaders.Action
но я надеюсь, что есть какой-то способ сделать это без ручного сопоставления действий SOAP с OperationContracts.
Я пытаюсь проверить атрибуты метода перед его выполнением.
4 ответа
Это заняло у меня целую вечность, но я нашел способ, который лучше, чем поиск и прохождение через весь контракт:
string action = operationContext.IncomingMessageHeaders.Action;
DispatchOperation operation =
operationContext.EndpointDispatcher.DispatchRuntime.Operations.FirstOrDefault(o =>
o.Action == action);
// Insert your own error-handling here if (operation == null)
Type hostType = operationContext.Host.Description.ServiceType;
MethodInfo method = hostType.GetMethod(operation.Name);
И вот вы здесь. Вы можете получить атрибуты или делать все что угодно.
Примечание: у вас может возникнуть желание попробовать использовать OperationSelector в DispatchRuntime. Проблема, которую я обнаружил, заключалась в том, что в моем случае, на определенном этапе обработки, OperationSelector был нулевой ссылкой. Если у вас есть доступ к этому свойству, оно, вероятно, быстрее и надежнее в использовании, чем "сканирование" OperationCollection, как описано выше.
Если OperationContext.CurrentIncomingMessageHeaders.Action
имеет значение null, вы можете сделать это - это немного более кратко:
string actionName = OperationContext.Current.IncomingMessageProperties["HttpOperationName"] as string;
Type hostType = operationContext.Host.Description.ServiceType;
MethodInfo method = hostType.GetMethod(actionName);
Основываясь на ответах @Aaronaught и @TimDog, а также на этот вопрос SO, я нашел решение, которое должно работать как для REST, так и для SOAP.
///<summary>Returns the Method info for the method (OperationContract) that is called in this WCF request.</summary>
System.Reflection.MethodInfo GetActionMethodInfo(System.ServiceModel.OperationContext operationContext ){
string bindingName = operationContext.EndpointDispatcher.ChannelDispatcher.BindingName;
string methodName;
if(bindingName.Contains("WebHttpBinding")){
//REST request
methodName = (string) operationContext.IncomingMessageProperties["HttpOperationName"];
}else{
//SOAP request
string action = operationContext.IncomingMessageHeaders.Action;
methodName = operationContext.EndpointDispatcher.DispatchRuntime.Operations.FirstOrDefault(o =>o.Action == action).Name;
}
// Insert your own error-handling here if (operation == null)
Type hostType = operationContext.Host.Description.ServiceType;
return hostType.GetMethod(methodName);
}
Средство интеграции Castle WCF позволяет вам делать это (среди многих полезных вещей) с помощью прокси-серверов DynamicProxy. Посмотрите здесь.
Там не так много документации, поэтому для документации о том, как ее использовать, лучше взглянуть на ее тесты.