Ejemplo de controlador de formulario HTML
Este ejemplo muestra cómo extender el Modelo de programación de web Windows Communication Foundation (WCF) para administrar exposiciones de formulario HTML, como aquéllos generados por un explorador web.
Nota
Para generar y ejecutar este ejemplo, es necesario que esté instalado .NET Framework versión 3.5. Para abrir los archivos de solución y proyecto se necesita Visual Studio 2008.
Analizar formularios de datos
Los envíos del formulario HTML están codificados como una serie de pares de nombre y valor dentro de un cuerpo de entidad HTTP POST con un tipo de contenido application/x-www-form-urlencoded. El método ParseQueryString es capaz de analizar estos valores en NameValueCollection cuando se hayan presentado con una cadena de cuerpo de entidad sin formato. Para permitir pasar esta colección de nombre/valor como un parámetro a una operación del servicio WCF, la clase FormDataProcessor
en el ejemplo utiliza el punto de extensibilidad IDispatchMessageFormatter.
La implementación de clase FormDataProcessor
de DeserializeRequest utiliza ParseQueryString para analizar el cuerpo de la entidad en NameValueCollection. La Consulta integrada de lenguaje de Microsoft (LINQ) se utiliza para rellenar los parámetros de método adicionales, cuyos valores están disponibles a través de UriTemplateMatch utilizados para enviar la solicitud a la operación.
public void DeserializeRequest(System.ServiceModel.Channels.Message message, object[] parameters)
{
if (WebOperationContext.Current.IncomingRequest.ContentType
!= "application/x-www-form-urlencoded")
throw new InvalidDataException("Unexpected content type");
Stream s = StreamMessageHelper.GetStream(message);
string formData = new StreamReader(s).ReadToEnd();
NameValueCollection parsedForm =
System.Web.HttpUtility.ParseQueryString(formData);
UriTemplateMatch match =
message.Properties["UriTemplateMatchResults"] as UriTemplateMatch;
ParameterInfo[] paramInfos = operation.SyncMethod.GetParameters();
var binder = CreateParameterBinder( match );
object[] values = (from p in paramInfos
select binder(p)).ToArray<Object>();
values[paramInfos.Length - 1] = parsedForm;
values.CopyTo(parameters, 0);
}
private Func<ParameterInfo, object> CreateParameterBinder(UriTemplateMatch match)
{
QueryStringConverter converter = new QueryStringConverter();
return delegate( ParameterInfo pi )
{
string value = match.BoundVariables[pi.Name];
if (converter.CanConvert(pi.ParameterType) && value != null)
return converter.ConvertStringToValue(value,
pi.ParameterType);
else
return value;
};
}
Extienda WebHttpBehavior con un RequestFormatter personalizado
Puede derivar una clase de WebHttpBehavior para extender WCF en tiempo de ejecución para cada operación. En el ejemplo, FormProcessingBehavior
invalida GetRequestDispatchFormatter para complementar un FormDataFormatter
para cualquier operación de invocación de Web cuyo último parámetro sea NameValueCollection.
public class FormProcessingBehavior : WebHttpBehavior
{
protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
//Messages[0] is the request message
MessagePartDescriptionCollection parts =
operationDescription.Messages[0].Body.Parts;
//This formatter looks for [WebInvoke] operations that have
// their last parameter typed as NameValueCollection
if (operationDescription.Behaviors.Find<WebInvokeAttribute>()
!= null &&
parts.Count > 0 &&
parts[parts.Count - 1].Type == typeof(NameValueCollection))
{
return new FormDataRequestFormatter(operationDescription);
}
else
{
return base.GetRequestDispatchFormatter(
operationDescription, endpoint);
}
}
}
Implementar un formulario de procesamiento de servicio
FormProcessingBehavior
oculta los detalles del procesamiento del formulario HTML. La implementación del servicio se puede escribir a continuación sin un conocimiento especial de formularios HTML, como se muestra en el código muestra siguiente.
[OperationContract]
[WebInvoke(UriTemplate = "ProcessForm/{templateParam1}/{templateParam2}")]
public Message ProcessForm(string templateParam1, string templateParam2, NameValueCollection formData)
{
DumpValues(Console.Out, templateParam1, templateParam2, formData);
return StreamMessageHelper.CreateMessage(
MessageVersion.None, "",
"text/plain",
delegate(Stream output)
{
TextWriter writer = new StreamWriter(output);
DumpValues(writer, templateParam1, templateParam2, formData);
}
);
}
Nota
Para obtener una descripción detallada de la clase StreamMessageHelper
, veaEjemplo de secuencia de estilo de inserción..
Hospedar el servicio de procesamiento de formulario
El servicio se hospeda utilizando la clase ServiceHost. El FormProcessingBehavior
personalizado se agrega manualmente a ServiceEndpoint antes de llamar a Open como se muestra en el código siguiente.
ServiceHost host = new ServiceHost(typeof(Service), new Uri("https://localhost:8000/FormTest"));
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");
endpoint.Behaviors.Add(new FormProcessingBehavior());
Además, el extremo HTTP GET que existe de forma predeterminada se quita (el extremo que genera la página de ayuda HTML predeterminada) deshabilitando ServiceMetadataBehavior y ServiceDebugBehavior como se muestra en el ejemplo de código siguiente.
ServiceMetadataBehavior smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb != null)
{
smb.HttpGetEnabled = false;
smb.HttpsGetEnabled = false;
}
ServiceDebugBehavior sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();
if (sdb != null)
{
sdb.HttpHelpPageEnabled = false;
}
Ejecutar el ejemplo
Para ver el resultado del ejemplo, compile y ejecute el proyecto HtmlFormProcessing
y a continuación, navegar por https://localhost:8000/FormTest con un explorador web.
Consulte también
Otros recursos
Ejemplo de secuencia de estilo de inserción
Copyright © 2007 Microsoft Corporation. Reservados todos los derechos.