以编程方式从 WCF Web HTTP 服务帮助页面中删除方法?
Programmatically remove methods from the WCF Web HTTP Service Help Page?
如何以编程方式从 WCF Web HTTP Service Help Page 中删除服务方法?我仍然希望显示帮助页面,但我需要从中删除特定方法——而不更改 ServiceContract。
我尝试通过自定义 IEndpointBehavior 从 ServiceEndpoints 中删除服务方法,如下所示:
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
var operationsToRemove = endpointDispatcher.DispatchRuntime.Operations.Where(op => this.IsDeprecated(op)).ToList();
foreach (var operation in operationsToRemove)
{
endpointDispatcher.DispatchRuntime.Operations.Remove(operation);
}
}
...并且在调用已弃用的方法时,我收到 "Method not allowed" 错误(根据需要)。
我还尝试按照 this article 中的步骤省略 WSDL/auto-generated 客户端的服务方法,但这似乎不会影响帮助页面。
您可以通过编程方式进行,但我认为这种方式不适合生产环境。 Microsoft 在 System.ServiceModel.Web.dll 中隐藏了 HelpPage 的实现,并且没有可扩展点来更改此行为。
但是我们知道当前的实现,我们可以使用反射来实现 HelpPage 方法的动态管理。但是 MS 可以更改合同和实施细节,我们的实施将被破坏。所以,我强烈不建议在真实环境中使用它。
这是自定义的 BadCustomHelpPageWebHttpBehavior(继承自 WebHttpBehavior)。构造函数采用一组方法从帮助页面中排除:
public class BadCustomHelpPageWebHttpBehavior : WebHttpBehavior
{
/// <summary>
/// Creates BadCustomHelpPageWebHttpBehavior
/// </summary>
/// <param name="ignoredMethodNames">Array of method names to ignore in Help Page</param>
public BadCustomHelpPageWebHttpBehavior(string[] ignoredMethodNames)
{
m_ignoredMethodNames = ignoredMethodNames;
}
/// <summary>
/// Remove methods to display in Help Page by names passed in the constructor
/// </summary>
public override void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
base.ApplyDispatchBehavior(endpoint, endpointDispatcher);
if (m_ignoredMethodNames == null || m_ignoredMethodNames.Length == 0)
return;
DispatchOperation helpOperation = endpointDispatcher.DispatchRuntime.Operations.FirstOrDefault(o => o.Name == "HelpPageInvoke");
if(helpOperation == null)
return;
IOperationInvoker helpInvoker = helpOperation.Invoker;
Type helpInvokerType = CreateInternalSystemServiceWebType("System.ServiceModel.Web.HelpOperationInvoker");
FieldInfo helpPageFieldInfo = helpInvokerType.GetField("helpPage",
BindingFlags.Instance | BindingFlags.NonPublic);
if (helpPageFieldInfo != null)
{
object helpPage = helpPageFieldInfo.GetValue(helpInvoker);
Type helpPageType = CreateInternalSystemServiceWebType("System.ServiceModel.Dispatcher.HelpPage");
Type operationHelpInformationType =
CreateInternalSystemServiceWebType("System.ServiceModel.Dispatcher.OperationHelpInformation");
Type dictionaryType = typeof (Dictionary<,>);
Type[] operationInfoDictionaryGenericTypes = {typeof (string), operationHelpInformationType};
Type operationInfoDictionaryType = dictionaryType.MakeGenericType(operationInfoDictionaryGenericTypes);
FieldInfo operationInfoDictionaryFieldInfo = helpPageType.GetField("operationInfoDictionary",
BindingFlags.Instance | BindingFlags.NonPublic);
if (operationInfoDictionaryFieldInfo != null)
{
object operationInfoDictionary = operationInfoDictionaryFieldInfo.GetValue(helpPage);
object operationInfoDictionaryReplaced = RemoveHelpMethods(operationInfoDictionary,
operationInfoDictionaryType);
operationInfoDictionaryFieldInfo.SetValue(helpPage, operationInfoDictionaryReplaced);
}
}
}
private object RemoveHelpMethods(object operationInfoDictionary, Type operationInfoDictionaryType)
{
Debug.Assert(m_ignoredMethodNames != null);
var operationInfoDictionaryReplaced = Activator.CreateInstance(operationInfoDictionaryType);
var operationInfoDictionaryAsEnumerable = operationInfoDictionary as IEnumerable;
if (operationInfoDictionaryAsEnumerable != null)
{
foreach (var operationInfoEntry in operationInfoDictionaryAsEnumerable)
{
object key = operationInfoEntry.GetType().GetProperty("Key").GetValue(operationInfoEntry);
object value = operationInfoEntry.GetType().GetProperty("Value").GetValue(operationInfoEntry);
string name = value.GetType().GetProperty("Name").GetValue(value) as string;
if (m_ignoredMethodNames.Contains(name) == false)
{
operationInfoDictionaryReplaced.GetType()
.GetMethod("Add")
.Invoke(operationInfoDictionaryReplaced, new[] {key, value});
}
}
}
return operationInfoDictionaryReplaced;
}
private static Type CreateInternalSystemServiceWebType(string requestedType)
{
return typeof (WebServiceHost).Assembly.GetType(requestedType);
}
private readonly string[] m_ignoredMethodNames;
}
要使用此 class 只需将此行为添加到您的端点:
host.Description.Endpoints[0].Behaviors.Add(new BadCustomHelpPageWebHttpBehavior(new[] { "EchoWithGet" })
{
HelpEnabled = true
});
可以在此处找到此示例的完整源代码,包括简单的 WCF HTTP 服务器:
https://github.com/knyu15/BadCustomHelpPageWebHttpBehavior
可能更好的方法是用您的自定义页面替换 WCF HelpPage。详细的例子可以在这里找到:
。但这并没有回答您的直接问题。
如何以编程方式从 WCF Web HTTP Service Help Page 中删除服务方法?我仍然希望显示帮助页面,但我需要从中删除特定方法——而不更改 ServiceContract。
我尝试通过自定义 IEndpointBehavior 从 ServiceEndpoints 中删除服务方法,如下所示:
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
var operationsToRemove = endpointDispatcher.DispatchRuntime.Operations.Where(op => this.IsDeprecated(op)).ToList();
foreach (var operation in operationsToRemove)
{
endpointDispatcher.DispatchRuntime.Operations.Remove(operation);
}
}
...并且在调用已弃用的方法时,我收到 "Method not allowed" 错误(根据需要)。
我还尝试按照 this article 中的步骤省略 WSDL/auto-generated 客户端的服务方法,但这似乎不会影响帮助页面。
您可以通过编程方式进行,但我认为这种方式不适合生产环境。 Microsoft 在 System.ServiceModel.Web.dll 中隐藏了 HelpPage 的实现,并且没有可扩展点来更改此行为。
但是我们知道当前的实现,我们可以使用反射来实现 HelpPage 方法的动态管理。但是 MS 可以更改合同和实施细节,我们的实施将被破坏。所以,我强烈不建议在真实环境中使用它。
这是自定义的 BadCustomHelpPageWebHttpBehavior(继承自 WebHttpBehavior)。构造函数采用一组方法从帮助页面中排除:
public class BadCustomHelpPageWebHttpBehavior : WebHttpBehavior
{
/// <summary>
/// Creates BadCustomHelpPageWebHttpBehavior
/// </summary>
/// <param name="ignoredMethodNames">Array of method names to ignore in Help Page</param>
public BadCustomHelpPageWebHttpBehavior(string[] ignoredMethodNames)
{
m_ignoredMethodNames = ignoredMethodNames;
}
/// <summary>
/// Remove methods to display in Help Page by names passed in the constructor
/// </summary>
public override void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
base.ApplyDispatchBehavior(endpoint, endpointDispatcher);
if (m_ignoredMethodNames == null || m_ignoredMethodNames.Length == 0)
return;
DispatchOperation helpOperation = endpointDispatcher.DispatchRuntime.Operations.FirstOrDefault(o => o.Name == "HelpPageInvoke");
if(helpOperation == null)
return;
IOperationInvoker helpInvoker = helpOperation.Invoker;
Type helpInvokerType = CreateInternalSystemServiceWebType("System.ServiceModel.Web.HelpOperationInvoker");
FieldInfo helpPageFieldInfo = helpInvokerType.GetField("helpPage",
BindingFlags.Instance | BindingFlags.NonPublic);
if (helpPageFieldInfo != null)
{
object helpPage = helpPageFieldInfo.GetValue(helpInvoker);
Type helpPageType = CreateInternalSystemServiceWebType("System.ServiceModel.Dispatcher.HelpPage");
Type operationHelpInformationType =
CreateInternalSystemServiceWebType("System.ServiceModel.Dispatcher.OperationHelpInformation");
Type dictionaryType = typeof (Dictionary<,>);
Type[] operationInfoDictionaryGenericTypes = {typeof (string), operationHelpInformationType};
Type operationInfoDictionaryType = dictionaryType.MakeGenericType(operationInfoDictionaryGenericTypes);
FieldInfo operationInfoDictionaryFieldInfo = helpPageType.GetField("operationInfoDictionary",
BindingFlags.Instance | BindingFlags.NonPublic);
if (operationInfoDictionaryFieldInfo != null)
{
object operationInfoDictionary = operationInfoDictionaryFieldInfo.GetValue(helpPage);
object operationInfoDictionaryReplaced = RemoveHelpMethods(operationInfoDictionary,
operationInfoDictionaryType);
operationInfoDictionaryFieldInfo.SetValue(helpPage, operationInfoDictionaryReplaced);
}
}
}
private object RemoveHelpMethods(object operationInfoDictionary, Type operationInfoDictionaryType)
{
Debug.Assert(m_ignoredMethodNames != null);
var operationInfoDictionaryReplaced = Activator.CreateInstance(operationInfoDictionaryType);
var operationInfoDictionaryAsEnumerable = operationInfoDictionary as IEnumerable;
if (operationInfoDictionaryAsEnumerable != null)
{
foreach (var operationInfoEntry in operationInfoDictionaryAsEnumerable)
{
object key = operationInfoEntry.GetType().GetProperty("Key").GetValue(operationInfoEntry);
object value = operationInfoEntry.GetType().GetProperty("Value").GetValue(operationInfoEntry);
string name = value.GetType().GetProperty("Name").GetValue(value) as string;
if (m_ignoredMethodNames.Contains(name) == false)
{
operationInfoDictionaryReplaced.GetType()
.GetMethod("Add")
.Invoke(operationInfoDictionaryReplaced, new[] {key, value});
}
}
}
return operationInfoDictionaryReplaced;
}
private static Type CreateInternalSystemServiceWebType(string requestedType)
{
return typeof (WebServiceHost).Assembly.GetType(requestedType);
}
private readonly string[] m_ignoredMethodNames;
}
要使用此 class 只需将此行为添加到您的端点:
host.Description.Endpoints[0].Behaviors.Add(new BadCustomHelpPageWebHttpBehavior(new[] { "EchoWithGet" })
{
HelpEnabled = true
});
可以在此处找到此示例的完整源代码,包括简单的 WCF HTTP 服务器: https://github.com/knyu15/BadCustomHelpPageWebHttpBehavior
可能更好的方法是用您的自定义页面替换 WCF HelpPage。详细的例子可以在这里找到: 。但这并没有回答您的直接问题。