C# 在WCF REST 4中,是否可以将HTML作为响应格式之一返回
我有一个我正在编写的服务,打算由多个调用方使用,包括那些无法接收或解析XML或JSON的调用方 我知道可以使用原始流从服务响应返回HTML,但我希望能够根据客户端传递的Accepts类型头返回XML、JSON或HTML中的一种 我可以用单独的URL来实现,但这将取代一个已经有一个定义良好的API层的系统 是否有这样做的例子,或者是否有人知道管道的哪些部分需要延长C# 在WCF REST 4中,是否可以将HTML作为响应格式之一返回,c#,wcf,rest,C#,Wcf,Rest,我有一个我正在编写的服务,打算由多个调用方使用,包括那些无法接收或解析XML或JSON的调用方 我知道可以使用原始流从服务响应返回HTML,但我希望能够根据客户端传递的Accepts类型头返回XML、JSON或HTML中的一种 我可以用单独的URL来实现,但这将取代一个已经有一个定义良好的API层的系统 是否有这样做的例子,或者是否有人知道管道的哪些部分需要延长 (附录):我已经知道自动格式选择并启用了它,但我想从一个端点支持所有三种(或更多)格式(HTML、JSON、XML等)。是的,这是可能
(附录):我已经知道自动格式选择并启用了它,但我想从一个端点支持所有三种(或更多)格式(HTML、JSON、XML等)。是的,这是可能的。但是您需要创建一个新的消息格式化程序,它知道如何在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();
}
}
公共类StackOverflow_10519075
{
[DataContract(Name=“Person”,Namespace=”“)]
公共阶层人士
{
[数据成员]
公共字符串名称{get;set;}
[数据成员]
公共整数{get;set;}
}
[服务合同]
公共接口测试
{
[WebGet]
Person GetPerson();
}
公共类服务:ITest
{
公众人物
{
返回新人{Name=“John Doe”,年龄=33};
}
}
公共类MyHtmlLaWareFormatter:IDispatchMessageFormatter
{
IDispatchMessageFormatter原件;
公共MyHtmlLaWareFormatter(IDispatchMessageFormatter原件)
{
this.original=原件;
}
public void反序列化请求(消息,对象[]参数)
{
this.original.DeserializeRequest(消息、参数);
}
公共消息序列化回复(MessageVersion MessageVersion,对象[]参数,对象结果)
{
MyUseHtmlExtension-useHtml=OperationContext.Current.Extensions.Find();
if(useHtml!=null&&useHtml.UseHtmlResponse)
{
StringBuilder sb=新的StringBuilder();
sb.AppendLine(“结果“+useHtml.OperationName+”);
sb.AppendLine(“结果“+useHtml.OperationName+”);
sb.AppendLine(“”+result.GetType().FullName+””);
sb.附录(“”);
foreach(result.GetType().GetProperties()中的var prop)
{
string line=string.Format(“{0}:{1}”,prop.Name,prop.GetValue(result,null));
sb.追加行(“- ”+行+“
”);
}
sb.附录(“
”);
byte[]bytes=Encoding.UTF8.GetBytes(sb.ToString());
Message reply=Message.CreateMessage(messageVersion,null,新的RawBodyWriter(字节));
Add(WebBodyFormatMessageProperty.Name,新的WebBodyFormatMessageProperty(WebContentFormat.Raw));
HttpResponseMessageProperty httpResp=新的HttpResponseMessageProperty();
reply.Properties.Add(HttpResponseMessageProperty.Name,httpResp);
httpResp.Headers[HttpResponseHeader.ContentType]=“text/html”;
回复;
}
其他的
{
返回原始.SerializeReply(messageVersion、参数、结果);
}
}
类别:BodyWriter
{
专用字节[]字节;
公共RawBodyWriter(字节[]字节)
:base(真)
{
this.bytes=字节;
}
受保护的重写无效OnWriteByContents(XmlDictionaryWriter编写器)
{
writer.writeStarteElement(“二进制”);
writer.WriteBase64(this.bytes,0,this.bytes.Length);
writer.writeedelement();
}
}
}
公共类MyHtmlAwareInspector:IDispatchMessageInspector
{
接收请求后的公共对象(ref消息请求、IClientChannel通道、InstanceContext InstanceContext)
{
HttpRequestMessageProperty httpRequest=(HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
字符串accept=httpRequest.Headers[HttpRequestHeader.accept];
string operationName=request.Properties[WebHttpDispatchOperationSelector.HttpOperationNamePropertyName]作为字符串;
如果(接受==“文本/html”)
{
OperationContext.Current.Extensions.Add(新的MyUseHtmlExtension{UseHtmlResponse=true,OperationName=OperationName});
}
返回null;
}
SendReply之前的公共无效(参考消息回复,对象关联状态)
{
}
}
类MyUseHtmlExtension:IExtension
{
公共无效附加(OperationContext所有者){}
公共无效分离(OperationContext所有者){}
公共bool UseHtmlResponse{get;set;}
公共字符串操作名{get;set;}
}
公共类MyHtmlLaWareEndpointBehavior:IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint端点、BindingParameterCollection bindingParameters)
{
}
公共空间