WCF Service Receiving Null Values from DataContract - c#

My team is developing a WCF service to communicate with database tables. Lately, we have been noticing that if we insert a new record to some of the tables, the integer and Boolean values would not be saved to the record, but strings would work just fine.
It appeared that functions in the service that receive a DataContract class as a parameter would have null values for all their non-string properties.
I have set up a new class to test this out:
[DataContract]
public class MyObject
{
private string _Name;
[DataMember]
public string Name
{
get { return _Name; }
set { _Name = value; }
}
private int? _TestInt;
[DataMember]
public int? TestInt
{
get { return _TestInt; }
set { _TestInt = value; }
}
public MyObject()
{
_Name = "";
_TestInt = 0;
}
}
I have added functions to my service to simply return the value of the properties in the above class:
[OperationBehavior]
public string GetMyName(MyObject myObject)
{
return myObject.Name;
}
[OperationBehavior]
public int? GetMyTestInt(MyObject myObject)
{
return myObject.TestInt;
}
I have configured the service reference on my client application to not reuse types in referenced assemblies.
This is the code I use to test on the client:
MyObject record = new MyObject();
record.Name = "This is Me";
record.TestInt = 5;
int? returnValue = _client.GetMyTestInt(record);
string message;
if (returnValue == null)
message = "Integer value is null.";
else
message = "Integer value is " + returnValue.ToString();
MessageBox.Show(message, _client.GetMyName(record));
The code above shows a message that the integer returned by my service is null, instead of the 5 that I assigned it. GetMyName, however, does return the proper value for my string, which displays as the caption of my message box.
Why is it that the service seems to be receiving null values?

You have to add the [DataMember] attribute to the backing field.
Change your contract like this:
[DataContract]
public class MyObject
{
[DataMember] // data contract on backing field
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
[DataMember] // data contract on backing field
private int? _TestInt;
public int? TestInt
{
get { return _TestInt; }
set { _TestInt = value; }
}
public MyObject()
{
_Name = "";
_TestInt = 0;
}
}

In DataContract Add the Property attribute as
[DataMember(IsRequired = true)]

Related

C# - Detect when string is beyond [MaxLength(#)] and truncate?

I have a object class like so:
public class MyObject
{
[MaxLength(128)]
public string Name {get; set;}
}
However, when I make MyObject with a string for Name of more than 128 characters, I can set it and it works. This causes issues down the line because when I go to insert this object into the database, it exceptions due to the string being to long for that column in the table.
How would I go about making sure that a string that is too long gets truncated? And how can I detect when that happens so I can log it?
In the setter you can add some validation.
public class MyObject
{
private string name;
public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrEmpty(value) || value.Length <= 128)
{
name = value;
}
else
{
//log? do something or truncate
name = value.Substring(0, 127);
}
}
}
}
Alternatively I don't like it but I tried to make it work with an Attribute and made it easier to scale with a helper class.
public class MyObject
{
private string name;
[MaxLength(128, ErrorMessage = "String is longer than {1} characters and has been truncated.")]
public string Name
{
get { return name; }
set
{
name = value.Validate(GetType().GetProperty(MethodBase.GetCurrentMethod().Name.Substring(4)).GetCustomAttributes(false));
}
}
}
public static class Tools
{
public static string Validate(this string value, object[] attributes)
{
if (attributes.FirstOrDefault(x => x is MaxLengthAttribute) is MaxLengthAttribute maxLengthAttribute)
{
if (maxLengthAttribute.IsValid(value))
{
return value;
}
else
{
//LogMethod(maxLengthAttribute.FormatErrorMessage(maxLengthAttribute.MaximumLength.ToString()));
return value.Substring(0, maxLengthAttribute.Length - 1);
}
}
return value;
}
}

How can I tell if a key was ever defined in a deserialized JSON object in .NET?

I'm using C#/.NET 4.5 to deserialize a JSON object to a native .NET type. The JSON looks like:
{
id: 841,
runningTime: 33.8643736,
title: "Test title"
}
...and the class it deserializes to looks like:
public class Slide
{
public double runningTime
{
get;
set;
}
public string title
{
get;
set;
}
public int id
{
get;
set;
}
}
...using this code to deserialize it:
// given serializer is an instance of JavaScriptSerializer
var slide = serializer.Deserialize<Slide>(json);
This works just fine and I can read properties on the object as if I was directly reading the JSON.
But, what if title is an optional key in the JSON? I can check if it's null after deserializing, but that's not perfect because title could have legitimately been set to null in the JSON itself, and I need to know if the key itself was defined. Using some placeholder value for the title like "UNDEFINED" is also pretty hacky.
So, if I'm using JavaScriptDeserializer to deserialize JSON, how can I tell if a key was defined in the JSON in the first place vs. explicitly set to null?
I assume checking for null is not sufficient since the JSON could contain a null. So you could do this:
public class Slide
{
public bool HasTitle { get; private set; }
public double runningTime
{
get;
set;
}
private string _title;
public string title
{
get { return _title; }
set { _title = value; HasTitle = true; }
}
public int id
{
get;
set;
}
}
Now check "HasTitle" to see if the title property was ever set.
Without changing too much of the rest of your code, you can change the way you define your properties. Nullable<T> gives a good model for a helper structure, but only applies to value types. A version that also works for reference types, except without the special compiler and runtime support (not needed here), is easily made:
public struct Optional<T>
{
private readonly bool hasValue;
private readonly T value;
public Optional(T value) {
this.hasValue = true;
this.value = value;
}
public bool HasValue {
get { return hasValue; }
}
public T Value {
get {
if (!hasValue)
throw new InvalidOperationException();
return value;
}
}
public T GetValueOrDefault() {
return value;
}
public T GetValueOrDefault(T #default) {
return hasValue ? value : #default;
}
}
Add methods as needed.
When you have this, you can then change your class to mark your properties as optional:
public class Slide
{
private Optional<double> _runningTime;
private Optional<string> _title;
private Optional<int> _id;
public double runningTime
{
get { return _runningTime.GetValueOrDefault(); }
set { _runningTime = new Optional<double>(value); }
}
public string title
{
get { return _title.GetValueOrDefault(); }
set { _title = new Optional<string>(value); }
}
public int id
{
get { return _id.GetValueOrDefault(); }
set { _id = new Optional<int>(value);
}
}
You can then determine whether a property setter was ever called, and add support for explicitly unsetting properties:
public bool IsIdSet() {
return _id.HasValue;
}
public void ResetId() {
_id = default(Optional<int>);
}

How to convert DataTable to List<T> while watching for nulls

Movie Class
public class Movie
{
#region Properties
public string Name { get { return _name; } set { _name = value; } }
public string Producer { get { return _producer; } set { _producer = value; } }
public int Rating { get { return _rating; } }
public Image Covor { get; set; }
public string Description { get { return _description; } }
public int ReleaseYear { get { return _releaseYear; } set { _releaseYear = value; }}
#endregion
#region Private Fields
private string _name;
private string _producer;
private int _rating;
private string _description;
private int _releaseYear;
#endregion
#region Constructors
public Movie()
{
}
public Movie(string name, int yearRelease)
{
this._name = name;
this._releaseYear = yearRelease;
}
public Movie(string name, int yearRelease, string producer)
{
this._name = name;
this._releaseYear = yearRelease;
this._producer = producer;
}
#endregion
}
My attempt
foreach (DataRow movieRow in MovieTable().AsEnumerable())
{
if (movieRow["Producer"] != DBNull.Value)
{
Movie movie = new Movie()
{
Name = (string)movieRow["Name"],
Producer = (string)movieRow["Producer"],
ReleaseYear = (int)movieRow["Release Year"]
};
movieList.Add(movie);
}
else
{
Movie movie = new Movie()
{
Name = (string)movieRow["Name"],
ReleaseYear = (int)movieRow["Release Year"]
};
movieList.Add(movie);
}
}
This is my code so far I'm trying to convert a Table to a List. The only problem is DBNull's.
I would like to update the entire table to a list, this works currently for 2 situations, but I need for the List to contain all the information if it exists. I could create elseif statements to handle every possible scenario but there has to be a way better way to figure out if the type is DBNull and if not set the property correctly.
If there's any confusion tell me what it is and I'll explain further.
One option is to incorporate the null-check into the set-statements wherever you need them, using shorthand code:
Name = (movieRow["Name"] == DBNull.Value) ?
(string)movieRow["Name"] :
string.Empty,
// Producer will be given a value if it exists, or null otherwise:
Producer = (movieRow["Producer"] == DBNull.Value) ?
(string) movieRow["Producer"] :
null,
...
You can replace string.Empty with null or vice versa of course, if that suits you better.
Edit: Just a very basic clarification, since you state you are new to programming: This shorthand notation means "if firstValue is true, return secondValue, otherwise, return thirdValue"
var result = firstValue ? secondValue : thirdValue;
One option: you can check IsNull(column):
Movie movie = new Movie()
{
Name = movieRow.IsNull("Name")
? (string)null : (string)movieRow["Name"],
Producer = movieRow.IsNull("Producer")
? (string)null : (string)movieRow["Producer"],
// etc..
};
movieList.Add(movie);

Using reflection to set properties for wcf datacontract

I have a wcf service, dynamically calling wcf service through wsdl file at client. Now I want to set the properties of a method inside my wcf service. I had properties which are complextypes, and In each complex type I had 30 to 4o complex types. I cannot touch the service, only thing is using reflection assing values to the service datacontract and using methodInfo.Invoke(pass constructed object array). Client will pass input parameters for datacontract in dictionary. Is recursion need to navigate through inner classes of a complextype and set values.
Sample Code:
public CompositeType GetTestDataUsingDataContract(CompositeType composite, string str, int i,EmployeeIn obj)
{
///code here
}
**DataContract for CompositeType**
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
EmployeeIn employeeValue;
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
[DataMember]
public EmployeeIn EmploValue
{
get { return employeeValue; }
set { employeeValue = value; }
}
}
EmployeeIn Class
[DataContract]
public class EmployeeIn
{
bool UserIsOnline = true;
string UserName = "DANGER";
[DataMember]
public bool BoolValue
{
get { return UserIsOnline; }
set { UserIsOnline = value; }
}
[DataMember]
public string StringValue
{
get { return UserName; }
set { UserName = value; }
}
}
Using reflection I want to set these properties.
Here is a working code for setting properties via Reflection with property name provided by string:
void SetPropertyValue(object obj, string propertyPath, object value)
{
System.Reflection.PropertyInfo currentProperty = null;
string[] pathSteps = propertyPath.Split('/');
object currentObj = obj;
for (int i = 0; i < pathSteps.Length; ++i)
{
Type currentType = currentObj.GetType();
string currentPathStep = pathSteps[i];
var currentPathStepMatches = Regex.Match(currentPathStep, #"(\w+)(?:\[(\d+)\])?");
currentProperty = currentType.GetProperty(currentPathStepMatches.Groups[1].Value);
int arrayIndex = currentProperty.PropertyType.IsArray ? int.Parse(currentPathStepMatches.Groups[2].Value) : -1;
if (i == pathSteps.Length - 1)
{
currentProperty.SetValue(currentObj, value, arrayIndex > -1 ? new object[] { arrayIndex } : null);
}
else
{
if (currentProperty.PropertyType.IsArray)
{
currentObj = (currentProperty.GetValue(currentObj) as Array).GetValue(arrayIndex);
}
else
{
currentObj = currentProperty.GetValue(currentObj);
}
}
}
}
Now you can use this function to set properties like, for example:
SetPropertyValue(someClass, "SomeInt", 4);
SetPropertyValue(someClass, "ArrayProperty[5]/Char", (char)2);
SetPropertyValue(someClass, "TestField", new SomeOtherClass());

How can I test this method? [duplicate]

I am using WCF Test Client (WcfTestClient.exe) for testing one of my wcf services.
I have a message contract which has a list of DataContracts as :
My message contract is as follows :
[MessageContract]
public class UpdateInvoiceStatusesRequest
{
private List<InvoiceStatusHistory> _invoiceStatusHistory;
[MessageBodyMember(Order = 0)]
public List<InvoiceStatusHistory> InvoiceStatusHistory
{
get { return _invoiceStatusHistory; }
set { _invoiceStatusHistory = value; }
}
}
and my data contract is :
[DataContract]
public class InvoiceStatusHistory
{
private int _invoiceId;
private int _status;
private string _comment;
private string _timeStamp;
[DataMember]
public int InvoiceId
{
get { return _invoiceId; }
set { _invoiceId = value; }
}
[DataMember]
public string Comment
{
get { return _comment; }
set { _comment= value; }
}
[DataMember]
public int Status
{
get { return _status; }
set { _status = value; }
}
[DataMember]
public string TimeStamp
{
get { return _timeStamp; }
set { _timeStamp = value; }
}
}
when i am using WcfTestClient.exe to test the service with UpdateInvoiceStatusesRequest message contract it shows the value of InvoiceStatusHistory as length = 0, now i don't know how can i add the objects of InvoiceStatusHistory in List<InvoiceStatusHistory> ?
Does anyone has any idea about it, please help me?
Type length=1 in the box. A + sign will appear next to the request parameter name. Click on it, then on the [0] node which indicates the first element in the array and set its values as usual.

Categories