It looks like serverside cannot receive the passed values, requestVersion.Ping is empty.
namespace Communication
{
public class DataForRequestVersion
{
public string Ping = "";
}
public class DataForResponseVersion
{
public string Pong = "";
public string Version = "";
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
Communication.DataForResponseVersion Version(Communication.DataForRequestVersion requestVersion);
}
//Server
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceImplementation : WCFSimple.Contract.IService
{
public Communication.DataForResponseVersion Version(Communication.DataForRequestVersion requestVersion)
{
//Here requestVersion.Ping is EMPTY
Communication.DataForResponseVersion responseVersion = new Communication.DataForResponseVersion();
responseVersion.Pong = requestVersion.Ping;
responseVersion.Version = "MyApp v" + Settings.version;
return responseVersion;
}
}
//Client makes a request here
Communication.DataForRequestVersion requestVersion = new Communication.DataForRequestVersion();
requestVersion.Ping = DateTime.Now.ToString(Settings.DayTimePreciseFormat);
//Here requestVersion.Ping has a value
Communication.DataForResponseVersion responseVersion =
Service.Version(requestVersion);
What am I missing?
UPDATE
My application works very well, both sides communicate by passing custom data classes without any problem. However I tried to modify test client which one only sends-receives current time as string and made its parameter a bit complex; from string to custom data class. Main solution's application can send Version request and receive the answer. So I think my little test client got a problem.
Here is the pastebin code:
2nd UPDATE:
Some moderator doesn't allow me to answer my own question, I don't know why, I found a very similar question and the guy answered his own too. To help others next time I'm explaining the reason; I used namespace instead of creating class...And I fixed:
//namespace Communication
public class Communication
You need to label your request (and response) classes with the [DataContract] attribute, and their properties with the [DataMember] attribute:
[DataContract]
public class DataForRequestVersion
{
[DataMember]
public string Ping = "";
}
try using [DataContract] on your Data...classes... and [DataMember] on their fields...
Change the fields in DataForRequestVersion DataForResponseVersion classes to properties. By Default DatacontractSerializer will serialize public properties.
Related
I want to create and consume a WCF Service in Silverlight. I have created a service that returns this model from a database:
namespace SilverlightWithWCFService.Web
{
[DataContract]
public class Customer
{
[DataMember]
public string CustomerName { get; set; }
[DataMember]
public string CompanyName { get; set; }
[DataMember]
public string ContactName { get; set; }
}
}
The service looks like this:
namespace SilverlightWithWCFService.Web
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class SampleService
{
[OperationContract]
public List<Customer> CustomerList()
{
var custList = new List<Customer>();
// populate custList
return custList;
}
}
}
}
In my Silverlight application, I added a Service Reference. This method calls the service operation:
public Page()
{
InitializeComponent();
SampleServiceClient client = new SampleServiceClient();
client.CustomerListCompleted += new EventHandler<CustomerListCompletedEventArgs>(client_CustomerListCompleted);
client.CustomerListAsync();
}
void client_CustomerListCompleted(object sender, CustomerListCompletedEventArgs e)
{
CustomerGrid.ItemsSource = e.Result;
}
So my question is: I don't know how the Silverlight work with WCF. Do I have to serialize something on WCF side and deserialize the return value on client side? If so, what code is missing? (Where?)
UPDATE:
I think based on some online questions. Should I deserialize the returned e.Result in the completed event code?
Do I have to serialize something on WCF side and deserialize the return value on client side?
No, when you consume the webservice the underlying code will do all that for you.
Don't get hung up on it being Silverlight. Just think of Silverlight as the same as a console application. Whatever one has to do in the console app to consume the webservices, one will have to do in Silverlight. The only difference is that you will need to handle the calls in an async manner, but that is separate from the consuming of the webservice which your question pertains.
Note there was a competing technology to do all the updates of the webservice during a compile. That was called RIA services and that is a different animal all together.
I would recommend you use WCF web services, but update the size of the send/receive buffers for you will max those out easily on any true data transfers.
I have created one WCF service Application. There are few methods in Service1.svc.
Here is my IService1.cs
[OperationContract]
GetUserDetailsByEmail_Result GetUserDetailsByEmail(string email);
Here is my Service.svc.cs
public class Service1 : IService1
{
#region GetUserDetails
public GetUserDetailsByEmail_Result GetUserDetailsByEmail(string email)
{
return (new UserManager()).GetUserDetailsByEmail(email);
}
#endregion
}
Here GetUserDetailsByEmail_Result is Complex type created in DemoModel.edmx. It contain some Scalar Property.
Basically what I am trying to do is, I want to call this method from Client(c#) side. Here is my Client Side code
//svc.GetUserDetailsByEmailCompleted += new EventHandler<GetUserDetailsByEmailCompletedEventArgs>(svc_GetUserDetailsByEmailCompleted);
GetUserDetailsByEmail_Result dtbUserDetails = svc.GetUserDetailsByEmailAsync(loginName);
Here svc is the object of Service1Client. Here I am simply calling wcf method. It gives me an error
Cannot implicitly convert type 'void' to 'Demo.DemoServiceReference_Client.GetUserDetailsByEmail_Result'
It works when I use svc_GetUserDetailsByEmailCompleted method. But I want the return data directly in dtbUserDetails. How can I achieve this? Is there any changes in my WCF service or in my client side? Or in WCF method declaration?
You either need to create an object and bind the data to it like some of the people in the comments suggested then mark each property like so:
[DataContract(Namespace = "MyServiceContract.Service1.ComplexObject")]
public class ComplexObject
{
[DataMember(Order = 1, IsRequired = true)]
public String DbItem1{ get; private set; }
[DataMember(Order = 2, IsRequired = false)]
public ComplexBlobData DbItem2{ get; set; }
}
Or if you can open up the DemoModel.edmx(Code Behind) and mark it all with data contract the same way you would mark your own object.
Bottom line anything not marked is not going over the wire.
I got an Employee class and each employee has a list of applied leaves. Is it possible to have the list AppliedLeave as a [DataMember] in WCF?
[DataContract]
public class Employee
{
[DataMember]
public string UserID { get; set; }
[DataMember]
public int EmployeeNumber { get; set; }
[ForeignKey("EmployeeUserID")]
[DataMember]
public List<Leave> AppliedLeave
{
get { return _appliedLeaves; }
set { _appliedLeaves = value; }
}
private List<Leave> _appliedLeaves = new List<Leave>();
...
}
Is there any other way to do this?
thank you for your consideration of this matter
I extend my Question
This is my Leave Class:
[DataContract]
public class Leave
{
[Key()]
[DataMember]
public Guid LeaveId { get; set; }
[DataMember]
public string LeaveType { get; set; }
[DataMember]
public DateTime StartDate { get; set; }
[DataMember]
public string EmployeeUserID { get; set; }
}
this shows ServiceContract ---->
[ServiceContract]
public interface IEmployeeService
{
[OperationContract]
Employee GetEmployeeByUserId(string userId);
[OperationContract]
void AssignSupervisor(string userId, string supervisorUserId);
[OperationContract]
void DeleteEmployeeByUserId(string userId);
....
}
In Client application,
EmployeeServiceClient employeeService = new EmployeeServiceClient();
Employee employee = employeeService.GetEmployeeByUserId(id);
But when Employee gathered from the service its shows Null for leaves,
Can somebody help me? what have I done wrong here?
Yes, it is possible to return generics from WCF service operations.
But by default they are casted to Array on client side. This can be customized while proxy generation.
WCF: Serialization and Generics
Also you have to decorate the service with all the types to which generics can be resolved, using KnownTypeAttribute.
Known Types and the Generic Resolver
I also found my server side list would always arrive at the client as a null pointer. After browsing around a lot for this problem it strikes me it is nearly always denied at first ("your code should work")
Found the issue.. I had configured my solution using one "WCF Service" project and one "Winforms app" project with a generated service reference. Both interface and implementation of Service1 were in the WCF service project, as expected. But any list member returned null.
When I put my IService1.cs = the interface only = in a separate class library instead, reference the class library on both sides (using) and generate the service reference again, my list does work ! The generated code on the client side looks much simpler.
I did not need any special attributes, change service reference configuration, or interface references for this.
You could use IList<T> instead of List<T>.
As a beginner to WCF i want to implement a call to the Active Directory Service which gets all Users, the method looks like this:
[OperationContract]
SearchResultCollection GetAllUsers();
SearchResultCollection is not serializable so i have to make something like this:
[DataContract]
SearchResultCollection
So i have to make my own wrapper class which inherits the SearchResultCollection or use IDataContractSerializer. Both solutions seems not easy.
The question: How is the "standard" approach to use .NET Classes as a return type in a WCF service?
(Writing a own DataContract for my own class seems easy. ;))
The DataContract route will suffice here. The standard way is to decorate your class with the relevant attributes and it will be consumable by WCF in methods:
[DataContract]
public sealed class CustomerResponse
{
[DataMember]
public Guid CustomerReference { get; set; }
}
[ServiceContract]
public interface IWcfMessagingService
{
[OperationContract]
CustomerResponse GetCustomer();
}
If the class is not serializable, I don't think even wrapping it will work.
However, the SearchResultCollection is itself returned from a WCF method, so you could just pass that straight through your own service, or at the very least, wrap it successfully.
I think your best bet is create your own simple POCO class to represent SearchResult, and return a list of these objects. Really you want to be able to control exactly the information you need to send back from the service. For example:
[Serializable]
public class MySearchResult
{
public string Name { get; set; }
public string Email { get; set; }
}
And simply iterate the searech results and pull out the properties you need like so:
var results = new List<MySearchResult>();
foreach (SearchResult r in searchResultCollection)
{
results.Add(new MySearchResult
{
Name = searchResult.Properties["Name"],
Email = searchResult.Properties["Email"]
});
}
That way the xml being sent back isn't bloated with all the properties you don't need AND you can serialize your own List<MySearchResult> return results. And by the way I have no idea if the Name and Email properties exist I am just showing an example.
I think I would just return a List of User where User is a custom User class flagged as Serializable. The method that gets the data from active directory can populate the User class by looping through the result.
I'm attempting to test a [MessageContract] class against an existing sample message, and I'm looking for a way to simplify development by reading the sample message file into an instance of my [MessageContract] class and seeing how it worked out (I'm dealing with a particularly complex contract here, of non-WCF origin).
My [MessageContract] class looks something like this:
[MessageContract(IsWrapped = true, WrapperName = "wrapper", WrapperNamespace = "somens")]
public class RequestMessage
{
[MessageHeader(Name = "HeaderElem", Namespace = "otherns")]
public XElement CorrelationTimeToLive { get; set; }
[MessageBodyMember(Name = "id", Namespace = "somens")]
public XElement id { get; set; }
}
I can read the file into an instance of the Message class, using code such as the following:
var xr = XmlReader.Create("sample_message.xml");
var msg = Message.CreateMessage(xr, int.MaxValue, MessageVersion.Soap12);
That's not particulary helpful, however, because it doesn't allow me to test my [MessageContract] class at all.
Somewhere in the guts of WCF is a system for turning this Message instance into an instance of a particular [MessageContract] class, but what is it?
I just learned how to do this the other day following a talk with a collegue. I think this is what you were asking to do.
namespace MessageContractTest
{
class Program
{
static void Main(string[] args)
{
string action = null;
XmlReader bodyReader = XmlReader.Create(new StringReader("<Example xmlns=\"http://tempuri.org/\"><Gold>109</Gold><Message>StackOverflow</Message></Example>"));
Message msg = Message.CreateMessage(MessageVersion.Default, action, bodyReader);
TypedMessageConverter converter = TypedMessageConverter.Create(typeof(Example), "http://tempuri.org/IFoo/BarOperation");
Example example = (Example)converter.FromMessage(msg);
}
}
[MessageContract]
public class Example
{
[MessageHeader]
public string Hello;
[MessageHeader]
public double Value;
[MessageBodyMember]
public int Gold;
[MessageBodyMember]
public string Message;
}
}
You will need to deserialize the XML into an instance of your data contract. This is what WCF is doing for you under the covers.
Here is a quick tutorial that will show you how to invoke the DataContractSerializer manually for your XML.