Different behavior between 'Service Reference' and 'Web Reference' - c#

I have WCF endpoint exposed as defined bellow,
<service name="MyApp.Server.Endpoint.Orange" behaviorConfiguration="MyTio.Server.Endpoint.OrangeBehavior">
<endpoint address="" binding="basicHttpBinding" contract="Host.Server.Contract.IMyAppApi" bindingNamespace="http://host.com/myapp">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
when I add a "Service Refrence" in .NET 3.5 we get the following class in the proxy which is perfectly fine:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="GetMemberBillersRequest", Namespace="http://schemas.datacontract.org/2004/07/Contract.MemberBillers")]
[System.SerializableAttribute()]
public partial class GetMemberBillersRequest : WCFClient.MyRequest {
[System.Runtime.Serialization.OptionalFieldAttribute()]
private int ApplicationIdField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private int ProductIdField;
[System.Runtime.Serialization.DataMemberAttribute()]
public int ApplicationId {
get {
return this.ApplicationIdField;
}
set {
if ((this.ApplicationIdField.Equals(value) != true)) {
this.ApplicationIdField = value;
this.RaisePropertyChanged("ApplicationId");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public int ProductId {
get {
return this.ProductIdField;
}
set {
if ((this.ProductIdField.Equals(value) != true)) {
this.ProductIdField = value;
this.RaisePropertyChanged("ProductId");
}
}
}
}
the issue is when you add the reference to the same service but in .NET 2.0
you get the following proxy for the same contract:
[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://schemas.datacontract.org/2004/07/Contract.MemberBillers")]
public partial class GetMemberBillersRequest : MyRequest {
private int applicationIdField;
private bool applicationIdFieldSpecified;
private int productIdField;
private bool productIdFieldSpecified;
/// <remarks/>
public int ApplicationId {
get {
return this.applicationIdField;
}
set {
this.applicationIdField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool ApplicationIdSpecified {
get {
return this.applicationIdFieldSpecified;
}
set {
this.applicationIdFieldSpecified = value;
}
}
/// <remarks/>
public int ProductId {
get {
return this.productIdField;
}
set {
this.productIdField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool ProductIdSpecified {
get {
return this.productIdFieldSpecified;
}
set {
this.productIdFieldSpecified = value;
}
}
}
both are identical except the proxy generated through .NET 2.0 has two additional fields:
productIdFieldSpecified and applicationIdFieldSpecified. the issue with these two fields are that if you don't set the them manually to true their corresponding fields (ApplicationId, ProductId ) will not be serialized and passed to the server!
can someone please explain to me what is happening here?
EDIT:
I have found that this is only happening for int types, not strings!
here is the data contract for this operation
[DataContract]
public class GetMemberBillersRequest : MyRequest
{
[DataMember]
public int ApplicationId { get; set; }
[DataMember]
public int ProductId { get; set; }
}

This is the expected behavior, and has been that way since .NET 1.0. You'll see that for any primitive type which is optional in the schema - either an attribute with use="optional", or an element with minOccurs="0".
If the attribute or element were missing, then the generated property cannot be set to null. Instead, the *specified field is set to false in that case. Check that field before you decide whether the "real" one is present or not.
Similarly, if you want to set the main property, then you have to set the *specified property to true, otherwise it won't get sent.
I'm sure you know, but I'm adding this for future readers: Yes, there are nullable types now. However, development on ASMX web services slowed down considerably with the advent of WCF. It does not surprise me that nullable properties were never implemented for primitive types.
Also, be aware of this: Microsoft: ASMX Web Services are a “Legacy Technology”.

It would be helpful to see your service code. I haven't used web service reference for a while but my guess is that if those fields are not optional add a IsRequired = True to your DataMemeber attribute and regenrate the proxy.

Related

Returning a Service reference object in WCF

I have written a core webservice. This webservice handles all the calculations, data operations, etc.
This webservice is in the same solution as my microservice.
My microservice Should communicate with my core webservice, and return the object it received from the core webservice. The problem is that it won't work, as when I start my solution it is unable to translate the reference object for the data contract.
The exception on the WCF test client:
error CS0644: 'System.ComponentModel.PropertyChangedEventHandler'
cannot derive from special class 'System.MulticastDelegate'
When I added the COREservice as a reference, It auto-generated classes that implemented INotifyPropertyChanged.
Now, I of course could write extensive converters that would convert all the objects received from the core webserver to object with the same name, but locally defined, only this would be a lot of work and I doubt there isn't any other faster/more elegant way of solving this.
IService:
[OperationContractAttribute(AsyncPattern = true)]
IAsyncResult BeginOperation(string Salesperson, decimal Timestamp, AsyncCallback asyncCallback, object state);
CoreWebservice.ReturnObj EndOperation (IAsyncResult result);
Service:
public CoreWebservice.ReturnObj Operation(string Salesperson = null, decimal? Timestamp = null, OperationContext opContext = null)
{
CoreWebservice.ReturnObj result = CoreService.Operation(Salesperson, Timestamp ?? default(decimal));
return result;
}
Endpoint:
<client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary1/Service1/"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_M3ApiCalls"
contract="COREservice.ApiCalls" name="BasicHttpBinding_M3ApiCalls" />
</client>
All the classes or "Resultobjects" are written in the same manner (paired with a result, and a recordresult class)
[Serializable()]
[DataContract]
[XmlSerializerFormat()]
[XmlRoot(ElementName = "CRS100MI_List",DataType = "System.Xml.XmlElement",Namespace = "http://www.the.namespace/of/company")]
public class CRS100MI_ListResult
{
[DataMember]
[System.Xml.Serialization.XmlElement(Order = 0)]
public string Result = "";
//etc....
[DataMember]
[System.Xml.Serialization.XmlElementAttribute(Order = 3)]
public List<CRS100MI_ListRecordResult> Record = new List<CRS100MI_ListRecordResult>();
public CRS100MI_ListResult Parse(List<Dictionary<string, string>> list)
{
//parse a list of dictionaries to fill the fields of the
//recordresult, and return the entire object populated with records.
return this;
}
}
[Serializable()]
[DataContract(Namespace = "http://www.rexel.nl/M3/ApiCalls")]
[XmlSerializerFormat()]
[XmlRoot(ElementName = "CRS100MI_ListRecord", DataType = "System.Xml.XmlElement", Namespace = "http://www.the.namespace/of/company")]
public class CRS100MI_ListRecordResult
{
[DataMember]
[System.Xml.Serialization.XmlElementAttribute(Order = 0)]
public string Result { get; set; }
[DataMember]
[System.Xml.Serialization.XmlElementAttribute(Order = 1)]
public string ErrorMessage { get; set; }
[DataMember]
[System.Xml.Serialization.XmlElementAttribute(Order = 2)]
public List<string> Messages { get; set; }
//etc...
}
So, to summarize:
COREservice is referenced by service reference by the MICROservice
COREservice returns an object, which is to be returned by the MICROservice
MICROservice is dependent on the COREservice
Error CS0644 is thrown, because it probably isn't able to derive the full class from the COREservice
Is this maybe solvable by how I reference to the COREservice? or is there perhaps another solution I have overlooked?

wcf request parameter is null when it reaches service

I am developing a wcf web service. It was working correctly during unit testing. A few days back, I changed the default namespace from 'tempuri' as explained in this link: http://blog.rebuildall.net/2010/11/10/wcf_service_namespaces and also added 'Order' Property to the datamembers i.e. like [DataMember(Order = 1)] of both request and response classes. Now in one OperationContract, some parameters are being read as null at server side even though value is passed at client side. I also noticed that the responses of a couple of OperationContracts were showing empty tags when there should have been value in those tags.
On searching, I found blog with a similar problem, but what caused their problem was a name mismatch of a parameter in client and server side. The link to the blog is : http://blog.functionalfun.net/2009/09/if-your-wcf-service-is-unexpectedly.html
Can anyone guide me here. Thanks in advance
I dunno if anyone else manages to get this error the way I did, but this was the problem:
I had defined my classes like below:
public class CompositeType
{
private bool boolValue;
private string stringValue = "";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
By removing those variable declarations and using auto-property syntax, I was able to get past the issue. i.e like :
public class CompositeType
{
[DataMember]
public bool BoolValue
{
get;
set;
}
[DataMember]
public string StringValue
{
get;
set;
}
}

WCF Rest Datamember and Array issue

I've created a WCF service and the service is receiving the XML structure with all the data but the PackageID and ServiceCode. The problem seems to be in public RequestPackages[] Packages in the Track class.
If I change it to RequestPackages in the code below then the element data will be passed into the service method and will show in the PackageID/ServiceCode elements.
If I have it as RequestPackages[] then I get this stepping through in debug in the xml for Packages Element: wcf.RequestPackages[0] and PackageID/ServiceCode are not available. I am stepping through debug to view xml data passed as it hits the service method. I'm not sure how to resolve it but I've probably overlooked something simple. Thanks
Below is the Xml structure being sent:
<Track>
<Packages>
<PackageId>1234567890</PackageId>
<ServiceCode>123</ServiceCode>
</Packages>
</Track>
Below is the Data contracts:
[DataContract(Namespace = "")]
[XmlArrayItemAttribute("Package")]
public partial class Track
{
private RequestPackages[] packagesField;
/// <remarks/>
[DataMember(Order=0, Name="Package")]
public RequestPackages[] Packages
{
get
{
return this.packagesField;
}
set
{
this.packagesField = value;
}
}
}
[DataContract(Namespace = "")]
[XmlSerializerFormat]
public partial class RequestPackages
{
private string packageIdField;
private string serviceCodeField;
/// <remarks/>
[DataMember(Order = 0)]
[XmlElementAttribute]
public string PackageId
{
get
{
return this.packageIdField;
}
set
{
this.packageIdField = value;
}
}
/// <remarks/>
[DataMember(Order=1)]
[XmlElementAttribute]
public string ServiceCode
{
get
{
return this.serviceCodeField;
}
set
{
this.serviceCodeField = value;
}
}
}
I was missing an element in the xml...
<Packages>
<RequestPackages>
<PackageId>1234567890</PackageId>
<ServiceCode></ServiceCode>
</RequestPackages>
</Packages>

Validating inherited attribute using DataAnnotations

I have MVC project that relies on webservices to provide data and those webservices are based on CMIS specification with custom functionality. I have several classes used as DataContracts, which were created by Visual Studio when I added references to services I am calling. I am using that class as a model to ensure I am able to send instances to the service and process correctly those sent back to me.
I also have views to edit instances of those classes and I would like to use DataAnnotations to validate the forms (usually [Required] atribute and sometimes display name change).
I do not want to put those atributes in service reference files because updating the reference would mean I will loose those atributes (at least I could not be sure everything is still the same after reference update).
My thought was to create child class that would only serve as tool to introduce DataAnnotations to atributes I know for sure I will be using (those that will not dissapear from DataContract class for sure). How would I accomplish such inheritance with code?
Example - I have this class created by VS in reference.cs file:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="LibraryRequest", Namespace="http://schemas.datacontract.org/2004/07/Agamemnon.Models")]
[System.SerializableAttribute()]
public partial class LibraryRequest : DocuLive.RepositoryServiceExt.Library {
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string PasswordField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string ServerField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private bool UseDefaultField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string UserNameField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Password {
get {
return this.PasswordField;
}
set {
if ((object.ReferenceEquals(this.PasswordField, value) != true)) {
this.PasswordField = value;
this.RaisePropertyChanged("Password");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Server {
get {
return this.ServerField;
}
set {
if ((object.ReferenceEquals(this.ServerField, value) != true)) {
this.ServerField = value;
this.RaisePropertyChanged("Server");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public bool UseDefault {
get {
return this.UseDefaultField;
}
set {
if ((this.UseDefaultField.Equals(value) != true)) {
this.UseDefaultField = value;
this.RaisePropertyChanged("UseDefault");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string UserName {
get {
return this.UserNameField;
}
set {
if ((object.ReferenceEquals(this.UserNameField, value) != true)) {
this.UserNameField = value;
this.RaisePropertyChanged("UserName");
}
}
}
}
I want to make sure that no matter what changes in reference.cs file (even that class itself), I will always have Username, Password and Server marked as [Required] in my "Edit" and "Delete" forms.
Thanks in advance
Honza
I would stay away from inheriting an autogenerated class. It would not solve your problem with the attributes - you would have to override every single property so you can add attributes to it.
One solution is to use hand-coded datacontracts instead of autogenerated references. You will have full control over when they change, and you can put the attributes you need in them.
Another solution is wrapping the contract in your view model. Like this:
public class LibraryRequestViewModel {
private LibraryRequest request;
public LibraryRequestViewModel(LibraryRequest request){
this.request = request;
}
[Required]
public string Password {
get { return this.request.Password; }
set { this.request.Password = value; }
}
// do this for all fields you need
}

Private List<CustomObject> property on WCF return value is not disposed during Garbage-Collection

I have a simple WCF service hosted in IIS7 using the HTTP protocol. The service contains a method which returns a custom object called Calendar. This object is very basic, and contains simple value-type properties, with the exception of one property, Holidays, which is of type List<IHoliday>. Holiday is again, a simple type comprised of value-type properties only.
The Calendar object is returned from the WCF service-method to an MVC controller, and is applied to a corresponding view. During memory-testing using dotTrace, it's apparent that the Calendar object is finalised by the GC, but interestingly, its Holidays property, which is empty, remains on the heap.
It's not a major performance-issue, taking up a mere 32 bytes, but I'm interested to know why the empty list is not disposed. I can provide code-samples, if necessary.
Source code and service configuration below:
public class Calendar : ICalendar
{
[DataMember] private IEnumerable<IHoliday> holidays = new List<IHoliday>();
[DataMember] private IEnumerable<IHolidayNotTaken> holidaysNotTaken = new List<IHolidayNotTaken>();
[DataMember] private IEnumerable<INonInstructionalDay> nonInstructionalDays = new List<INonInstructionalDay>();
[DataMember] private IEnumerable<ISchoolBreak> schoolBreaks = new List<ISchoolBreak>();
}
public class Holiday : IHoliday, IIdentifiable, IDisposable
{
[DataMember(Name = #"date")] [JsonProperty(PropertyName = #"date")] private string date;
[DataMember(Name = #"checked")]
[JsonProperty(PropertyName = #"checked")]
public bool Checked { get; set; }
/// <summary>
/// Gets or sets the end Holiday Id.
/// </summary>
/// <value> The holiday id. </value>
[DataMember(Name = #"id")]
[JsonProperty(PropertyName = #"id")]
public int HolidayId { get; set; }
/// <summary>
/// Gets or sets the end description for the holiday.
/// </summary>
/// <value> The description. </value>
[DataMember(Name = #"description")]
[JsonProperty(PropertyName = #"description")]
public string Description { get; set; }
/// <summary>
/// Gets or sets the date of the holiday.
/// </summary>
/// <value> The holiday date. </value>
[DataMember]
[JsonIgnore]
public DateTime Date { get; set; }
/// <summary>
/// Gets or sets the sort order for the holiday.
/// </summary>
/// <value> The sort order. </value>
[DataMember(Name = #"sortOrder")]
[JsonProperty(PropertyName = #"sortOrder")]
public int SortOrder { get; set; }
/// <summary>
/// Gets the <see cref="IIdentifiable.Type" /> of this instance.
/// </summary>
[DataMember(Name = #"type")]
[JsonProperty(PropertyName = #"type")]
public string Type { get; private set; }
/// <summary>
/// Invoked when this instance is serialising.
/// </summary>
/// <param name="streamingContext"> The streaming context. </param>
[OnSerializing]
private void OnSerialising(StreamingContext streamingContext)
{
date = Date.ToString(#"yyyy-MM-dd");
Type = GetType().ToString();
}
}
Service Method:
public Domain.Calendar GetCalendarByMember(string externalId)
{
try
{
using (var e = new EPlannerEntities())
{
var memberId = e.Members
.Where(m => m.ExternalId == externalId)
.Select(m => m.MemberId)
.SingleOrDefault();
if (memberId.Equals(0))
{
e.Members.AddObject(new Member { ExternalId = externalId.Trim() });
var calendar = new Domain.Calendar
{
DefaultViewId = 2,
MemberId = memberId,
IsWeekendsVisible = true,
TimeFormatId = 1,
DayBeginTime = new TimeSpan(0, 8, 0, 0),
DayEndTime = new TimeSpan(0, 16, 0, 0),
DateFormatId = 1
};
e.Calendars.AddObject(calendar);
e.SaveChanges();
return calendar;
}
return e.Calendars.Single(c => c.MemberId == memberId);
}
}
catch (Exception exception)
{
throw ErrorManager.FaultException(ExceptionType.Business, (int) CalendarErrorCodes.GeneralError, exception);
}
}
Service Configuration:
<services>
<service behaviorConfiguration="CalendarServiceBehavior" name="HMH.ePlanner.Services.Calendar">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="TCPBinding" name="TCPEndPoint" contract="HMH.ePlanner.Services.ICalendar">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="HTTPBinding" name="HttpEndPoint" contract="HMH.ePlanner.Services.ICalendar" />
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="TCPMexEndPoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/Calendar.svc" />
</baseAddresses>
</host>
</service>
</services>
The problem stems from the fact that the Holiday list is instantiated without specifying an UpperBound. Specifying an UpperBound ensures that the object is removed from the Heap after garbage-collection.
Make a partial class for Calendar (if partial needed) and add the IDisposable interface to it and manually null out holiday. Run dottrace again and see if the same happens.
I do not have an answer for your question because I do not see anything criminal in provided code.
The only recommendation I can made is to check if Session and Security are required in solution.
Now it is not consistent. Configuration enables it for client who uses TCP and disables it for HTTP.
P.S. bindingConfiguration is missed in configuration. Did you post everything?

Categories