【问题标题】:Is it possible in WCF REST 4 to return HTML as one of the response formats在 WCF REST 4 中是否可以将 HTML 作为响应格式之一返回
【发布时间】:2012-05-09 15:19:53
【问题描述】:

我正在编写一项服务,旨在供多个调用者使用,包括无法接收或解析 XML 或 JSON 的调用者。

我知道使用原始流从服务响应返回 HTML 是可能的,但我希望能够根据传递的 Accepts-Type 标头返回 XML、JSON 或 HTML 之一客户。

我可以使用单独的 URL 来做到这一点,但这正在替换已经具有良好定义的 API 层的系统。

有没有这样做的例子,或者有谁知道管道的哪些部分需要扩展?

(附录):我已经了解 AutomaticFormatSelection 并已启用它,但我想从一个端点支持所有三种(或更多)格式(HTML、JSON、XML 等)。

【问题讨论】:

    标签: c# wcf rest


    【解决方案1】:

    是的,这是可能的。但是您需要创建一个新的消息格式化程序,它知道如何在 CLR 类型(操作响应)和 HTML 页面之间进行转换。最简单的方法是将原始格式化程序包装在新格式化程序中,因此当您收到对带有 Accept: text/html 的请求的响应时,您使用您的逻辑,但对于其他请求,您使用原始格式化程序。

    不过,格式化程序无法访问传入的请求,因此我们也可以使用消息检查器来提供它。

    下面的代码显示了这种格式化程序/检查器对的一种可能实现。

    public class StackOverflow_10519075
    {
        [DataContract(Name = "Person", Namespace = "")]
        public class Person
        {
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
        }
        [ServiceContract]
        public interface ITest
        {
            [WebGet]
            Person GetPerson();
        }
        public class Service : ITest
        {
            public Person GetPerson()
            {
                return new Person { Name = "John Doe", Age = 33 };
            }
        }
        public class MyHtmlAwareFormatter : IDispatchMessageFormatter
        {
            IDispatchMessageFormatter original;
            public MyHtmlAwareFormatter(IDispatchMessageFormatter original)
            {
                this.original = original;
            }
    
            public void DeserializeRequest(Message message, object[] parameters)
            {
                this.original.DeserializeRequest(message, parameters);
            }
    
            public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
            {
                MyUseHtmlExtension useHtml = OperationContext.Current.Extensions.Find<MyUseHtmlExtension>();
                if (useHtml != null && useHtml.UseHtmlResponse)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine("<html><head><title>Result of " + useHtml.OperationName + "</title></head>");
                    sb.AppendLine("<body><h1>Result of " + useHtml.OperationName + "</h1>");
                    sb.AppendLine("<p><b>" + result.GetType().FullName + "</b></p>");
                    sb.AppendLine("<ul>");
                    foreach (var prop in result.GetType().GetProperties())
                    {
                        string line = string.Format("{0}: {1}", prop.Name, prop.GetValue(result, null));
                        sb.AppendLine("<li>" + line + "</li>");
                    }
                    sb.AppendLine("</ul></body></html>");
                    byte[] bytes = Encoding.UTF8.GetBytes(sb.ToString());
                    Message reply = Message.CreateMessage(messageVersion, null, new RawBodyWriter(bytes));
                    reply.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
                    HttpResponseMessageProperty httpResp = new HttpResponseMessageProperty();
                    reply.Properties.Add(HttpResponseMessageProperty.Name, httpResp);
                    httpResp.Headers[HttpResponseHeader.ContentType] = "text/html";
                    return reply;
                }
                else
                {
                    return original.SerializeReply(messageVersion, parameters, result);
                }
            }
    
            class RawBodyWriter : BodyWriter
            {
                private byte[] bytes;
    
                public RawBodyWriter(byte[] bytes)
                    : base(true)
                {
                    this.bytes = bytes;
                }
    
                protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
                {
                    writer.WriteStartElement("Binary");
                    writer.WriteBase64(this.bytes, 0, this.bytes.Length);
                    writer.WriteEndElement();
                }
            }
        }
        public class MyHtmlAwareInspector : IDispatchMessageInspector
        {
            public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
            {
                HttpRequestMessageProperty httpRequest = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
                string accept = httpRequest.Headers[HttpRequestHeader.Accept];
                string operationName = request.Properties[WebHttpDispatchOperationSelector.HttpOperationNamePropertyName] as string;
                if (accept == "text/html")
                {
                    OperationContext.Current.Extensions.Add(new MyUseHtmlExtension { UseHtmlResponse = true, OperationName = operationName });
                }
    
                return null;
            }
    
            public void BeforeSendReply(ref Message reply, object correlationState)
            {
            }
        }
        class MyUseHtmlExtension : IExtension<OperationContext>
        {
            public void Attach(OperationContext owner) { }
            public void Detach(OperationContext owner) { }
            public bool UseHtmlResponse { get; set; }
            public string OperationName { get; set; }
        }
        public class MyHtmlAwareEndpointBehavior : IEndpointBehavior
        {
            public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
            {
            }
    
            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
            }
    
            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            {
                endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MyHtmlAwareInspector());
                foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations)
                {
                    operation.Formatter = new MyHtmlAwareFormatter(operation.Formatter);
                }
            }
    
            public void Validate(ServiceEndpoint endpoint)
            {
            }
        }
        public static void Test()
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
            var endpoint = host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "");
            endpoint.Behaviors.Add(new WebHttpBehavior { AutomaticFormatSelectionEnabled = true });
            endpoint.Behaviors.Add(new MyHtmlAwareEndpointBehavior());
            host.Open();
            Console.WriteLine("Host opened");
    
            WebClient c;
    
            c = new WebClient();
            c.Headers[HttpRequestHeader.Accept] = "application/json";
            Console.WriteLine(c.DownloadString(baseAddress + "/GetPerson"));
            Console.WriteLine();
    
            c = new WebClient();
            c.Headers[HttpRequestHeader.Accept] = "text/xml";
            Console.WriteLine(c.DownloadString(baseAddress + "/GetPerson"));
            Console.WriteLine();
    
            c = new WebClient();
            c.Headers[HttpRequestHeader.Accept] = "text/html";
            Console.WriteLine(c.DownloadString(baseAddress + "/GetPerson"));
            Console.WriteLine();
    
            Console.Write("Press ENTER to close the host");
            Console.ReadLine();
            host.Close();
        }
    }
    

    【讨论】:

    • 哇太棒了@carlosfigueira,谢谢。我会看看并实现它。
    猜你喜欢
    • 2023-03-28
    • 1970-01-01
    • 2016-09-17
    • 2014-09-11
    • 1970-01-01
    • 2018-05-23
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多