vs2015 visual tutorial studio example consumir c# .net wcf

c# - tutorial - wcf visual studio 2017



El proxy del servicio WCF no establece la propiedad "FieldSpecified" (7)

Más información

En la MSDN here

En su respuesta, Shreesha explica que:

Los campos "especificados" solo se generan en parámetros opcionales que son estructuras. (int, datetime, decimal etc). Todas estas variables tendrán una variable adicional generada con el nombre Especificado.

Esta es una forma de saber si un parámetro se pasa realmente entre el cliente y el servidor.

Para elaborar, un entero opcional, si no se pasa, todavía tendría el valor de error de error 0. ¿Cómo se diferencia entre este y el que realmente se pasó con un valor 0? El campo "especificado" le permite saber si se pasa o no el entero opcional. Si el campo "especificado" es falso, el valor no se pasa. Si es verdadero, se pasa el entero.

en esencia, la única forma de configurar estos campos es establecerlos manualmente, y si no se configuran en verdadero para un campo que se estableció, entonces ese campo se perderá en el mensaje SOAP del servicio web llamada.

Lo que hice al final fue crear un método para recorrer todos los miembros del objeto, y si la propiedad se ha establecido, y si hay una propiedad llamada nombre _ Especificada, entonces establezca eso en verdadero.

Tengo un DataContract WCF que se parece a lo siguiente:

namespace MyCompanyName.Services.Wcf { [DataContract(Namespace = "http://mycompanyname/services/wcf")] [Serializable] public class DataContractBase { [DataMember] public DateTime EditDate { get; set; } // code omitted for brevity... } }

Cuando agrego una referencia a este servicio en Visual Studio, se genera este código proxy:

/// <remarks/> [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3082")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://mycompanyname/services/wcf")] public partial class DataContractBase : object, System.ComponentModel.INotifyPropertyChanged { private System.DateTime editDateField; private bool editDateFieldSpecified; /// <remarks/> [System.Xml.Serialization.XmlElementAttribute(Order=0)] public System.DateTime EditDate { get { return this.editDateField; } set { this.editDateField = value; this.RaisePropertyChanged("EditDate"); } } /// <remarks/> [System.Xml.Serialization.XmlIgnoreAttribute()] public bool EditDateSpecified { get { return this.editDateFieldSpecified; } set { this.editDateFieldSpecified = value; this.RaisePropertyChanged("EditDateSpecified"); } } // code omitted for brevity... }

Como puede ver, además de generar una propiedad de respaldo para EditDate , se EditDate una <propertyname>Specified adicional <propertyname>Specified . Todo bien, excepto que cuando hago lo siguiente:

DataContractBase myDataContract = new DataContractBase(); myDataContract.EditDate = DateTime.Now; new MyServiceClient.Update(new UpdateRequest(myDataContract));

EditDate no fue recogido por el punto final del servicio (no aparece en el XML transmitido).

Depuré el código y descubrí que, aunque estaba configurando EditDate , la propiedad EditDateSpecified no se configuraba como true ; por lo tanto, el serializador XML estaba ignorando el valor de EditDate , a pesar de que está establecido en un valor válido.

Como truco rápido, modifiqué la propiedad EditDate para que se pareciera a lo siguiente:

/// <remarks/> [System.Xml.Serialization.XmlElementAttribute(Order=0)] public System.DateTime EditDate { get { return this.editDateField; } set { this.editDateField = value; // hackhackhack if (value != default(System.DateTime)) { this.EditDateSpecified = true; } // end hackhackhack this.RaisePropertyChanged("EditDate"); } }

Ahora el código funciona como se esperaba, pero, por supuesto, cada vez que vuelvo a generar el proxy, se pierden mis modificaciones. Podría cambiar el código de llamada a lo siguiente:

DataContractBase myDataContract = new DataContractBase(); myDataContract.EditDate = DateTime.Now; myDataContract.EditDateSpecified = true; new MyServiceClient.Update(new UpdateRequest(myDataContract));

Pero eso también parece ser una pérdida de tiempo.

Entonces, finalmente, mi pregunta: ¿alguien tiene alguna sugerencia sobre cómo superar este comportamiento no intuitivo (y IMO roto) del generador proxy del servicio de Visual Studio, o simplemente me estoy perdiendo algo?


Aquí hay un proyecto simple que puede modificar los configuradores en el código WCF generado para que las propiedades opcionales establezcan automáticamente las * Banderas especificadas en verdadero cuando se establece el valor relacionado.

https://github.com/b9chris/WcfClean

Obviamente, hay situaciones en las que desea un control manual sobre el * Indicador especificado, por lo que no lo recomiendo a todos, pero en la mayoría de los casos de uso simples, los * Indicadores especificados son solo una molestia adicional y su configuración automática ahorra tiempo y, a menudo, es más intuitivo.

Tenga en cuenta que el comentario de Mustafa Magdy sobre otra respuesta aquí lo resolverá si usted controla el punto de publicación del Servicio web. Sin embargo, normalmente no controlo la publicación del Servicio Web y solo estoy consumiendo una, y tengo que hacer frente a las * Marcas especificadas en algún software simple donde me gustaría que esté automatizado. Así esta herramienta.


Cambiar las propiedades de la clase de proxy a tipo anulable

ej:

bool confirmado

¿Fecha y hora? comprobar Fecha


En lugar de cambiar los configuradores del código generado automáticamente, puede usar una clase de extensión para ''autospecificar'' (vincular el evento del controlador de cambios). Esto podría tener dos implementaciones: una "perezosa" ( Autospecify ) que usa reflexión para buscar fieldSpecified según el nombre de la propiedad, en lugar de enumerarlas todas para cada clase en algún tipo de declaración de cambio como Autonotify :

Perezoso

public static class PropertySpecifiedExtensions { private const string SPECIFIED_SUFFIX = "Specified"; /// <summary> /// Bind the <see cref="INotifyPropertyChanged.PropertyChanged"/> handler to automatically set any xxxSpecified fields when a property is changed. "Lazy" via reflection. /// </summary> /// <param name="entity">the entity to bind the autospecify event to</param> /// <param name="specifiedSuffix">optionally specify a suffix for the Specified property to set as true on changes</param> /// <param name="specifiedPrefix">optionally specify a prefix for the Specified property to set as true on changes</param> public static void Autospecify(this INotifyPropertyChanged entity, string specifiedSuffix = SPECIFIED_SUFFIX, string specifiedPrefix = null) { entity.PropertyChanged += (me, e) => { foreach (var pi in me.GetType().GetProperties().Where(o => o.Name == specifiedPrefix + e.PropertyName + specifiedSuffix)) { pi.SetValue(me, true, BindingFlags.SetField | BindingFlags.SetProperty, null, null, null); } }; } /// <summary> /// Create a new entity and <see cref="Autospecify"/> its properties when changed /// </summary> /// <typeparam name="T"></typeparam> /// <param name="specifiedSuffix"></param> /// <param name="specifiedPrefix"></param> /// <returns></returns> public static T Create<T>(string specifiedSuffix = SPECIFIED_SUFFIX, string specifiedPrefix = null) where T : INotifyPropertyChanged, new() { var ret = new T(); ret.Autospecify(specifiedSuffix, specifiedPrefix); return ret; } }

Esto simplifica la escritura de métodos de fábrica de conveniencia como:

public partial class MyRandomClass { /// <summary> /// Create a new empty instance and <see cref="PropertySpecifiedExtensions.Autospecify"/> its properties when changed /// </summary> /// <returns></returns> public static MyRandomClass Create() { return PropertySpecifiedExtensions.Create<MyRandomClass>(); } }

Un inconveniente (aparte de la reflexión, meh) es que tiene que usar el método de fábrica para crear instancias de sus clases o usar .Autospecify antes de (?) .Autospecify cambios en las propiedades con especificadores.

Sin reflejo

Si no te gusta la reflexión, puedes definir otra interfaz de clase de extensión +:

public static class PropertySpecifiedExtensions2 { /// <summary> /// Bind the <see cref="INotifyPropertyChanged.PropertyChanged"/> handler to automatically call each class''s <see cref="IAutoNotifyPropertyChanged.Autonotify"/> method on the property name. /// </summary> /// <param name="entity">the entity to bind the autospecify event to</param> public static void Autonotify(this IAutoNotifyPropertyChanged entity) { entity.PropertyChanged += (me, e) => ((IAutoNotifyPropertyChanged)me).WhenPropertyChanges(e.PropertyName); } /// <summary> /// Create a new entity and <see cref="Autonotify"/> it''s properties when changed /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static T Create<T>() where T : IAutoNotifyPropertyChanged, new() { var ret = new T(); ret.Autonotify(); return ret; } } /// <summary> /// Used by <see cref="PropertySpecifiedExtensions.Autonotify"/> to standardize implementation behavior /// </summary> public interface IAutoNotifyPropertyChanged : INotifyPropertyChanged { void WhenPropertyChanges(string propertyName); }

Y luego cada clase define el comportamiento:

public partial class MyRandomClass: IAutoNotifyPropertyChanged { public void WhenPropertyChanges(string propertyName) { switch (propertyName) { case "field1": this.field1Specified = true; return; // etc } } }

La desventaja de esto es, por supuesto, que las cadenas mágicas para los nombres de propiedades hacen que la refactorización sea difícil, ¿cuál podría ser el problema con el análisis de Expression ?


Ian, por favor, ignora mis respuestas anteriores, estaba explicando cómo chupar los huevos. He votado para eliminarlos.

¿Podría decirme qué versión de Visual Studio está utilizando, por favor?

En el cliente VS2005: en el código generado, obtengo los indicadores <property>Specified , pero no se genera ningún evento en el cambio de valores. Para pasar datos tengo que establecer el indicador <property>Specified .

En el cliente de Visual Web Developer 2008 Express: en el código generado, no obtengo <property>Specified indicadores <property>Specified , pero sí obtengo el evento al cambiar el valor.

Me parece que esta funcionalidad ha evolucionado y la Web Dev 2008 está más cerca de lo que está buscando y es más intuitiva, ya que no necesita establecer indicadores una vez que haya establecido un valor.

Bowthy


Puede que sea un poco poco intuitivo (¡y también me pillo desprevenido y tambaleándome!), Pero es la única forma adecuada de manejar elementos que podrían o no estar especificados en su esquema XML.

Y también puede parecer contraintuitivo que tengas que establecer la xyzSpecified tú mismo, pero en última instancia, esto te da más control, y WCF tiene que ver con los Cuatro Principios de SOA de ser muy explícitos y claros sobre tus intenciones.

Básicamente, así es como es, acostúmbrate a :-) No hay forma de "pasado" de este comportamiento, es la forma en que se diseñó el sistema WCF, y también por una buena razón.

Lo que siempre puede hacer es atrapar y manejar this.RaisePropertyChanged("EditDate"); evento y establezca la EditDateSpecified en un controlador de eventos para ese evento.


prueba esto

[DataMember(IsRequired=true)] public DateTime EditDate { get; set; }

Esto debería omitir la propiedad EditDateSpecified ya que el campo se especifica como se requiere