简体   繁体   中英

Programmatically remove methods from the WCF Web HTTP Service Help Page?

How do you programmatically remove service methods from the WCF Web HTTP Service Help Page ? I still want the Help page to show up, but I need to remove specific methods from it -- without changing the ServiceContract.

I have tried removing the service method from ServiceEndpoints via custom IEndpointBehavior, like so:

    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);
        }
    }

... and when a deprecated method is called, I get a "Method not allowed" error (as desired).

I have also tried to omit the service methods from the WSDL/auto-generated clients by following the steps in this article , but that doesn't seem to affect the Help page.

You can do it programmatically, but I'm believe the way to do it is not good for production environment. Implementation of HelpPage hidden by Microsoft in System.ServiceModel.Web.dll and there's no extensibility points to change this behavior.

But we know current implementation and we can use reflection to implement dynamic managing of methods for HelpPage. But contract and implementation details can be changed by MS and our implementation will be broken. So, I'm strongly don't recommend to use it in a real environment.

Here's a custom BadCustomHelpPageWebHttpBehavior (inherited from WebHttpBehavior). Constructor takes an array of methods to exclude from Help Page:

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;
}

To use this class just add this behavior to you endpoint:

host.Description.Endpoints[0].Behaviors.Add(new BadCustomHelpPageWebHttpBehavior(new[] { "EchoWithGet" })
{
    HelpEnabled = true
});

Full source code of this example including simple WCF HTTP server could be found here: https://github.com/knyu15/BadCustomHelpPageWebHttpBehavior

Possible the better way is to replace WCF HelpPage with your custom page. Detailed example could be found here: Customize the WebHttp Help Output in WCF . But this is not answering your immediate question, though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM