I am looking to place attributes on my WCF data contract members to validate string length and possibly use regex for more granular parameter validation.
I can the [Range] attribute for numeric and DateTime values and was wondering if any of you have found any other WCF Data Member attributes I can use for data validation. I have found a bevvy of attributes for Silverlight but not for WCF.
Add System.ComponentModel.DataAnnotations reference to your project.
The reference provides some DataAnnotations which are:
RequiredAttribute, RangeAttribute, StringLengthAttribute, RegularExpressionAttribute
you can in your datacontract like below.
[DataMember]
[StringLength(100, MinimumLength= 10, ErrorMessage="String length should be between 10 and 100." )]
[StringLength(50)] // Another way... String max length 50
public string FirstName { get; set; }
[DataMember]
[Range(2, 100)]
public int Age { get; set; }
[DataMember]
[Required]
[RegularExpression(#"\b[A-Z0-9._%-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b", ErrorMessage = "Invalid Mail id")]
public string Email { get; set; }
Hope this helps.
Manually Validating Values: You can manually apply the validation test by using the Validator class. You can call the ValidateProperty method on the set accessor of a property to check the value against the validation attributes for the property. You must also set both ValidatesOnExceptions and NotifyOnValidationError properties to true when data binding to receive validation exceptions from validation attributes.
var unsafeContact = Request["contactJSON"];
try
{
var serializer = new DataContractJsonSerializer(typeof(Contact));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(unsafeContact));
Contact = serializer.ReadObject(stream) as Contact;
stream.Close();
}
catch (Exception)
{
// invalid contact
}
Contact class:
[DataContract]
public sealed class Contact
{
/// <summary>
/// Contact Full Name
/// </summary>
/// <example>John Doe</example>
[DataMember(Name = "name", IsRequired = true)]
[StringLength(100, MinimumLength = 1, ErrorMessage = #"Name length should be between 1 and 100.")]
public string Name {
get
{
return HttpUtility.HtmlEncode(_name);
}
internal set
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Name" });
_name = value;
}
}
private string _name;
// ...
}
Try to look look for WCF Data Annotations. WCFDataAnnotations allows you to automatically validate WCF service operation arguments using System.ComponentModel.DataAnnotations attributes.
http://wcfdataannotations.codeplex.com/
Related
I have DataContract as below
[DataContract]
public class Test
{
public List<Validation> val { get; set; }
}
and my OperationContract as below
public bool TestValidation(Test t, out string message)
{
return ValidationUtility.ValidateFields(t.val, out message);
}
I am not getting how to set value for Test.val on WCF Test Client
Firstly, it seems like you're missing the DataMember attribute for your list.
[DataContract]
public class Test {
[DataMember]
public List <Validation> val { get; set; }
}
Also, ensure that the DataContract and DataMember attributes for Validation are set up properly as well. Then restart your WCF Test Client and try calling the service again.
Expand the objvalidation part on the Name column. A + sign should appear next to the request parameter name. You can then add elements and fill out their properties (Value column) by expanding each individual element you've added.
Good day everyone,
I have a doubt on my currently development, the thing is i've created a project using ntier and data application block for my data access layer so, i have a package named Entities where i create all my classes and i was trying to use error messages mapped to a resource file the problem is when i write the following code it marks up with error:
(Entity-Base-Clients)
public partial class Clients {
public Int32 Id {get;set;}
[Display(Name="Name",
ResourceType=typeof(Resources.Language))]
[Required(AllowEmptyStrings=false,
ErrorMessageResourceName="Id",
ErrorMessageResourceType=typeof(Resources.Language))]
public string Name {get;set;}
}
In the following code it marks up error in "Resources" (which is the folder where i put my resource files) and "Language" is the resource file.
But when i do the exactly the same thing on the "Model" folder didn't marks up any error
(Model-Clients)
public Int32 Id {get;set;}
[Display(Name="Name",
ResourceType=typeof(Resources.Language))]
[Required(AllowEmptyStrings=false,
ErrorMessageResourceName="Id",
ErrorMessageResourceType=typeof(Resources.Language))]
public string Name {get;set;}
}
Do i have doing something wrong? am i missing a reference or configuration of the RF?
Thanks in advance
[Display(Name = "Name"), Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName ="nameHasToBeGiven")]
public string name { get; set; }
this one is way easier
This is an old problem. To solve it I deactivated the EDMX Code generation and I created external TT files to generate :
DomainLayer : Contains EF EDMX classes (with navigation)
DataLayer : Contains stuff to query data
[Serializable]
public partial class Contact : _DomainLayer_Base
{
#region Primitive Properties
/// <summary>
/// Gets or sets Id.
/// </summary>
/// <value>The Id.</value>
public virtual int Id
{
get;
set;
}
/// <summary>
/// Gets or sets FK_Language.
/// </summary>
/// <value>The FK_Language.</value>
/// <remarks>
/// Foregn key of Contact
///
/// </remarks>
public virtual int FK_Language
{
get { return _fK_Language; }
set
{
try
{
_settingFK = true;
if (_fK_Language != value)
{
if (Language != null && Language.Id != value)
{
Language = null;
}
_fK_Language = value;
}
}
finally
{
_settingFK = false;
}
}
}
}
MetaDataLayer : Contains EF Independant classes with data annotations linked to resources (without navigation)
[Serializable]
public partial class Contact_MetaData : _MetaDataLayer_Base
{
[Display(Name = "Ety_Contact_Id" , ResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.MetaDataResources))]
[Required(ErrorMessageResourceName = "ErrMsgRequired",ErrorMessageResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.Resources))]
public virtual int Id
{
get;
set;
}
[Display(Name = "Ety_Contact_FK_Language" , ResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.MetaDataResources))]
[Required(ErrorMessageResourceName = "ErrMsgRequired",ErrorMessageResourceType = typeof(InnovaApp.Layers.ResourcesLayer.Properties.Resources))]
public virtual int FK_Language
{
get;
set;
}
MetaModels : Inside the portal, MetaModels are MetaData members containers. They contains data required by portal. Example :If you have a foreign key, the ForeignKey value will be in the MetaData but ListItems used to fill the lookup will be in the MetaModel.
EntityLayer : Contains EF EDMX
When I create a EF Query I prefix result with db :
When I use the data in the view, I use my MetaDataLayer :
public class ContactViewer_MetaModel : Contact_MetaData
To transfert data from DomainLayer to MetaDataLayer I Use Emit Mapper because My TT files guaranty same signature between Domain and MetaData.
toReturn = ObjectMapperManager.DefaultInstance.GetMapper<Contact, ContactViewer_MetaModel>().Map(dbContact);
and in the view :
#model InnovaApp.Layers.SecurityLayer.Models.MetaModels.Contact_MetaModel
#Html.HiddenFor(m => m.Id)
<ol class="olMainForm">
<li>
#Html.LabelFor(m => m.FK_Genre)
#Html.DropDownListFor(m => m.FK_Genre, Model.Genres)
#Html.ValidationMessageFor(m => m.FK_Genre)
</li>
</ol>
You can find the full source here :
https://myprettycms.codeplex.com
I have the following class I'd like to send from my WCF (C#) service to my client (WPF):
[DataContract]
public class OutputAvailableEventArgs
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Message { get; private set; }
[DataMember]
public bool IsError { get; private set; }
public OutputAvailableEventArgs(int id) : this(id, false, "") { }
public OutputAvailableEventArgs(int id, string output) : this(id, false, output) { }
public OutputAvailableEventArgs(int id, bool isError, string output)
{
ID = id;
IsError = isError;
Message = output;
}
}
It's used by the service as follows:
var channel = OperationContext.Current.GetCallbackChannel<IClientCallback>();
channel.OutputAvailable(new OutputAvailableEventArgs(1, false, "some message"));
At the client side, the members get their default values.
I tried marking them with IsRequired attribute but now the OutputAvailable at the client is not called. The code at the service side seems to run smoothly (I didn't notice anything with the debugger).
How can I transfer a DataContract class with WCF while maintaining the members' values?
(I saw solutions that suggested to use OnSerialized and OnDeserialized but I don't need just a default constructor.)
I saw many different solutions for this problem. For other people's sake I'll write some of them down + what worked for me:
It seems that in some cases specifying the items' order solves the problem. Please see this SO question for full details.
If it's some default initialization you're after, you can use OnSerialized and OnDeserialized methods to call your initialization methods.
I also tried using the IsRequired attribute on my DataMembers but still didn't get my objects.
What worked for me was adding NameSpace property in the DataContract attribute. Apparently, In order to have the contracts be considered equal, you must set the Namespace property on the DataContract to the same value on both sides.
I am having problem transfering my object from WCF to SL3.
interface IComposite {
ICollection<Child_A> Children{ get; set; }
}
[DataContract]
[knownType(typeof(ChildCollection))]
[knownType(typeof(ICollection<Child_A>))]
class Composite : IComposite {
ChildCollection c = null;
[DataMember]
public string Name { get;set;}
[DataMember]
public ICollection<Child_A> Children { get {
return c??(c=new ChildCollection());
} set;}
}
[CollectionDataContract]
class ChildCollection : List<Child_A> {
}
[DataContract]
class Child_A {
[DataMember]
string Name { get;set; }
}
[OperationContract]
Composite GetData(){
var data = new Composite();
data.Children.Add( new Child_A() { Name = "child_a_1" } );
return data;
}
When I call the service from SL3, I get the Composite object but no item in the list. There are other collection in Composite. When I set [DataMember(Order=0/1)] I get error nullreference error on client. And if I remove it, I get error Not Found. I tried KnowType and ServiceKnownType but did not work. I checked svcTrace, it simply says Serialization Error. Where I am doing wrong.
SVC TRACE
The InnerException message was 'Type 'xxxCoverageEntity' with data contract name 'xxxCoverageEntity : http://schemas.datacontract.org/2004/07/xxxBusinessEntities' is not expected. Add any types not known statically to the list of known types
Here xxxCoverageEntity is Child_A in sample
You need to annotate the collection with DataMember or it will not get serialized at all. You will also need to annotate the DataContract with KnownType(typeof(ChildCollection)) as otherwise it doesn't know what type of "thing" the ICollection is and therefore how to serialize it
Similarly you will need to add [DataMember] to Child_A Name property or it will not get serialized
I have a following problem. A customer requested a web service that returns data in following format:
<status>
<name1>Some name</name1>
...
</status>
But when an error occurs they want to get a following message:
<status>
<error>Error description</error>
</status>
I created a web service using WCF and in order to fulfill the requirements I defined a following service contract:
[ServiceContract]
public interface IPatronStatus
{
[OperationContract]
[ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))]
[WebGet(UriTemplate = "/service/status?user={unilogin}")]
StatusData GetPatronStatus(string unilogin);
}
And also defined a following base class:
[DataContract(Name="status")]
public class StatusData
{
}
And two derrived classes:
public class PatronStatusData : StatusData
{
private string _name;
[DataMember(Name = "name1", Order = 0)]
public string Name
{
get { return _name; }
set { _name = value; }
}
...
}
And:
public class UniLoginNotFoundError : StatusData
{
public UniLoginNotFoundError()
{ }
private string _description = "UniLoginNotFoundError";
[DataMember(Name = "error", Order = 0)]
public string Description
{
get
{
return _description;
}
}
}
The problem is that when I pull the data from the web service the data contract name ("status") and the names of the data members are ignored and the type's and properties' names are used.
Is it possible to use the custome names?
You should decorate both UniLoginNotFoundError and PatronStatusData with DataContract(Name="Something") to make this work. But you won't be allowed to set the same name ("status") for them.
In your particular case I'd better use single class with unused properties set to null.
[DataContract(Name="status")]
public class StatusData
{
private string _name;
private string _errorDescription = null;
[DataMember(Name = "name1", Order = 0, EmitDefaultValue=false)]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember(Name = "error", Order = 1, EmitDefaultValue=false)]
public string Description
{
get{ return _errorDescription ;}
set {_errorDescription =value ;}
}
...
}
Generally speaking, it's a mistake to want too much control over the XML generated by serializing a Data Contract. That's the trap of the XML Serializer. Define the contract in general terms, and have the clients just consume the result, which will generally be simple enough.