I am very new to WCF programmng and having some difficulties.
I have client application which collects student data and then that student data will be stored to the DB through a web services.
So I have student class in client side and when new student comes I create the student object and assigned collected values.
What is the most suitable way to pass this data to the services??
Options that I can follow is;
Option 1
public void InsertStudent(string id, string name, string address)
{
}
I feel this is not good. Because if I have to pass so may data the parameter list will get lengthy.
Option 2
define a data contract on service
public void InsertStudent(WcfStudent obj)
{
}
I feel this is good. But I have some issues with how to send the parameter(WcfStudent).
Do I need to create this WcfStudent object on my client side and pass the object.
WcfStudent obj=new WcfStudent()
obj.name=myStudent.name;
obj.id=myStudent.id;
client.InsertStudent(obj);
is this the correct way to to do this??
Please advice me.
Of course like you said second option is better. In WCF Project you have to create DataContract WcfStudent. In project which have service reference (this is what you call client) you have to just execute method (OperationContract) InsertStudent. How you create this object in theory it doesn't matter but I think it's a good practice to have in your 'client' also an object named for example StudentBO and create mapping between WcfStudent and StudentBO or use some tool for example Automapper.
If you're totally new in WCF please read about DataContract, DataMember.
Good luck!
UPDATE
Speaking about your comment would be better something like:
public WcfStudent(MyStudent myStudent)
{
this.Id= myStudent.Id;
this.Name= myStudent.Name;
}
Your WCF Service will contain the definition of your WcfStudent class, and it will define that class as a Data Contract (if you are not using separate DTOs).
Referencing the WCF Service in your client project, either via a WSDL file or via the Visual Studio interface, gives your client application visibility or knowledge on the public classes, interfaces, and whatnot of the Service. This should include the WcfStudent class. You can then proceed with utilizing this in your code through something like:
MyWcfService.WcfStudent student = new MyWcfService.WcfStudent();
//assign values, etc
Manipulate that student object inside your application as you see fit, and then call your web service when you are ready to persist.
client.InsertStudent (student);
You would typically use data contracts instead of individual parameters, because then you can easily version them; and extend them easily with additional optional parameters and still be backwards compatible.
Personally I like to follow the request/response pattern consistently:
public InsertStudentResponse InsertStudent(InsertStudentRequest request)
{
}
If you don't expect a result, the response type could be void of course.
The request object contains only what you need in order to complete te request. Nothing more, nothing less. For example, if you want to change the address of a student, don't call ModifyStudent while passing all student properties, but call MoveStudent and pass only the new address information; so that you have clearly defined business operations.
Concerning the naming of your operations, InsertStudent is a CRUD-like naming, while I prefer to name them in business terminology, like RegisterNewStudent or something.
Also don't forget about fault contracts: don't throw exceptions, throw faults.
Related
So I am sending entities over WCF. What I would like to do is to have an opportunity to alter the entities in any way I want before they go over. I do not have to do this in the WCF but I don't see another place to do it, as I want one single place to do it.
Open to suggestions though if anyone has another way to do it :)
I have the usual layers of DAL, Domain and Service. They all share a Common too.
I think you are talking about Message Inspectors
A message inspector is an extensibility object that can be used in the
service model's client runtime and dispatch runtime programmatically
or through configuration and that can inspect and alter messages after
they are received or before they are sent.
This sample implements a basic client and service message validation
mechanism that validates incoming messages against a set of
configurable XML Schema documents. Note that this sample does not
validate messages for each operation. This is an intentional
simplification.
Also take a look into IParameterInspector, here you can handle all input/output parameters in client and server side
I am not sure if I understood correctly what you are asking, but I'll give it a try.
I think that you might be looking for Data Transfer Objects (DTO). You can put all the needed data of your entities into a DTO before sending it to the service. The service then does the processing of the contained data and sends another DTO back to your client.
This way, you have full control over how the DTO is structured and what kind of data your service and client really need.
Expanding on Jen H's answer:
Instead of inspecting messages and dealing with the overhead of de-serializing the
already serialized results you could just perform your customization logic after you retrieve the results from your database and before you return them to the client. One way of doing that is shown below
public interface IDataTransferObject
{
void CustomizeMeSomehow();
}
[DataContract]
public class MyDataTransferObject : IDataTransferObject
{
public void CustomizeMeSomehow()
{
//Your custom logic here..
}
}
public class MyService
{
public List<MyDataTransferObject> GetObjects()
{
List<MyDataTransferObjects> items = Repository.RetrieveResults();
foreach (var item in items)
item.CustomizeMeSomehow();
return items;
}
}
Hi I have been reading some lecture notes and I cant work out why this method:
[OperationContract]
Student PostStudent (Student student);
Is good.
And this method is bad:
[OperationContract]
void PostStudent (string firstname, string lastname etc..);
Yet my implemented version is this:
[OperationContract]
void PostStudent(Student student);
So Im not sure if my implemented version is bad, Im also unsure how my lecturer got
Student PostStudent (Student student); // ?
Web services are built upon the use of messages. A message in WCF is defined by writing a class, which your Student class is, and (optionally) marking it with the DataContract attribute. This enables versioning and setting various properties on the properties of that class (although the latter effect can also be achieved using the MessageParameter attribute).
So yes, PostStudent (string firstname, string lastname etc..) is bad.
Whether or not to return something from that method is up to you. A void can be perfectly fine, because using for example SOAP you can return a Fault indicating why the user could not be created: no error means the creation went well.
When you want to inpect the created Student, you might as well define a PostStudentResult (or a PostResult<T>) class and return that, containing the properties Student (or T Result) and Status, where the first contains the student as it's created and the latter indicates whether or not the creation was successful.
Return values in Web services are not bad practice in general. So it is about the parameters. Data that belongs together should be wrapped in in Objects.
Further a Post method should not get an return value at all. You post it and in case of an error your will receive an Exception.
If your need to receive some student you should create an method like:
Student GetStudentByName(string name);
If it is a WCF then specifying Action can also be a good practice with Void methods.
Like evryone else said, having too many method parameters is bad practice. Any way I can see only one difference between your signature and the good signature you mentioned. Having the student object as return will give you the ability of having the Id of the student after addition in db for example. Same thing applies for any other calculated properties of the object. Have a void method will force you to load the object again which means an extra trip to server in case you wanted to use the object directly after posting it. Any way having void WCF method is not bad if returning the object is nothing but an extra bandwith.
I'm writing some software that modifies a Windows Server's configuration (things like MS-DNS, IIS, parts of the filesystem). My design has a server process that builds an in-memory object graph of the server configuration state and a client which requests this object graph. The server would then serialize the graph, send it to the client (presumably using WCF), the server then makes changes to this graph and sends it back to the server. The server receives the graph and proceeds to make modifications to the server.
However I've learned that object-graph serialisation in WCF isn't as simple as I first thought. My objects have a hierarchy and many have parametrised-constructors and immutable properties/fields. There are also numerous collections, arrays, and dictionaries.
My understanding of WCF serialisation is that it requires use of either the XmlSerializer or DataContractSerializer, but DCS places restrictions on the design of my object-graph (immutable data seems right-out, it also requires parameter-less constructors). I understand XmlSerializer lets me use my own classes provided they implement ISerializable and have the de-serializer constructor. That is fine by me.
I spoke to a friend of mine about this, and he advocates going for a Data Transport Object-only route, where I'd have to maintain a separate DataContract object-graph for the transport of data and re-implement my server objects on the client.
Another friend of mine said that because my service only has two operations ("GetServerConfiguration" and "PutServerConfiguration") it might be worthwhile just skipping WCF entirely and implementing my own server that uses Sockets.
So my questions are:
Has anyone faced a similar problem before and if so, are there better approaches? Is it wise to send an entire object graph to the client for processing? Should I instead break it down so that the client requests a part of the object graph as it needs it and sends only bits that have changed (thus reducing concurrency-related risks?)?
If sending the object-graph down is the right way, is WCF the right tool?
And if WCF is right, what's the best way to get WCF to serialise my object graph?
Object graphs can be used with DataContract serialization.
Note: Make sure you're preserving object references, so that you don't end up with multiple copies of the same object in the graph when they should all be the same reference, the default behavior does not preserve identity like this.
This can be done by specifying the preserveObjectReferences parameter when constructing a DataContractSerializer or by specifying true for the IsReference property on DataContractAttribute (this last attribute requires .NET 3.5SP1).
However, when sending object graphs over WCF, you have the risk of running afoul of WCF quotas (and there are many) if you don't take care to ensure the graph is kept to a reasonable size.
For the net.tcp transport, for example, important ones to set are maxReceivedMessageSize, maxStringContentLength, and maxArrayLength. Not to mention a hidden quota of 65335 distinct objects allowed in a graph (maxObjectsInGraph), that can only be overridden with difficulty.
You can also use classes that only expose read accessors with the DataContractSerializer, and have no parameterless constructors:
using System;
using System.IO;
using System.Runtime.Serialization;
class DataContractTest
{
static void Main(string[] args)
{
var serializer = new DataContractSerializer(typeof(NoParameterLessConstructor));
var obj1 = new NoParameterLessConstructor("Name", 1);
var ms = new MemoryStream();
serializer.WriteObject(ms, obj1);
ms.Seek(0, SeekOrigin.Begin);
var obj2 = (NoParameterLessConstructor)serializer.ReadObject(ms);
Console.WriteLine("obj2.Name: {0}", obj2.Name);
Console.WriteLine("obj2.Version: {0}", obj2.Version);
}
[DataContract]
class NoParameterLessConstructor
{
public NoParameterLessConstructor(string name, int version)
{
Name = name;
Version = version;
}
[DataMember]
public string Name { get; private set; }
[DataMember]
public int Version { get; private set; }
}
}
This works because DataContractSerializer can instantiate types without calling the constructor.
You got yourself mixed up with the serializers:
the XmlSerializer requires a parameter-less constructor, since when deserializing, the .NET runtime will instantiate a new object of that type and then set its properties
the DataContractSerializer has no such requirement
Check out the blog post by Dan Rigsby which explains serializers in all their glory and compares the two.
Now for your design - my main question is: does it make sense to have a single function that return all the settings, the client manipulates those and then another function which receives back all the information?
Couldn't you break those things up into smaller chunks, smaller method calls? E.g. have separate service methods to set each individual item of your configuration? That way, you could
reduce the amount of data being sent across the wire - the object graph to be serialized and deserialized would be much simpler
make your configuration service more granular - e.g. if someone needs to set a single little property, that client doesn't need to read the whole big server config, set one single property, and send back the huge big chunk - just call the appropriate method to set that one property
In short: Trying to write a wcf service for a winform-app that invokes a stored procedure on a webserver.
So far no problem - my service exposes the method "execStp(string nameOfStoredProcedure, stpParamList parameterList)"
[OperationContract]
int execStp(string stpName, srsWcfLib.Utilities.stpParamList paramList);
where stpParamList is another class holding of a third class stpParams (which basically holds a name/value pair of an SqlParameter
To add parameters to the list, I wrote a method in the second class
public void addParameter(string ParamName, object ParamValue)
{
this._Parameters.Add(new stpParam(ParamName, ParamValue));
}
List<stpParam> _Parameters = new List<stpParam>();
[DataMember]
public List<stpParam> Parameters
{
get { return _Parameters; }
set { _Parameters = value; }
}
When instantiating the List-class in the win-app
stpParamList stpParams = new stpParamList();
I can access stpParams.Parameters, but NOT stpParams.addParameter (name, value);
What am I missing (obviously)...?
Thank you,
Reinhard
WCF only brings over the properties to the client, not the functions. I forget the term they use, but it is basically just a property/field dump that gets sent through.
To solve this, reference the same Entity library in the client, and under "configure WCF Service" check "reuse reference" for that library.
Erich has nailed the problem on the head: WCF is a MESSAGE based transport system, e.g. you will transfer a serialized message of your object. The server-side object with any additional functions will be serialized into XML or a binary format, sent across the wire to the client.
The client however only has the XSD (XML Schema) file exposed by your service at its disposal - it will create a client-side class that has the same "data signature" on the wire - i.e. the same fields, by the same name and type - but it cannot magically recreate any functions and/or methods your server-side code has. All it can do is deserialize the message (text or binary) back into a data-only representation of the class.
This is not a bug or a problem of a binding - this is a fundamental design choice for WCF - the only connection between the client and the server is the serialized message - anything that can be represented in XML schema. It will happily serialize and deserialize data - but it cannot move code / behavior across. You're NOT passing the actual objects by reference like with a normal function call - the WCF runtime serializes your parameters into XML and sends it across.
Now if you do control both ends of the wire, e.g. both the client and the server, there is a way around this, which violates the SOA principles a bit (but it can be useful). If you put your service contracts and data contracts into a separate assembly Contracts.dll (a class library), and then reference it from both the server side and the client side, you can indeed actually share the common .NET type srsWcfLib.Utilities.stpParamList with all its functionality. In those cases, however, you'll need to do a bit more work on the client side and instantiate your client proxy manually in code (rather than have Visual Studio or svcutil create the client proxy for you), since you need to reference that shared contracts assembly and use its types directly (rather than creating client-side classes).
Marc
Background
I have made a Web Service in Visual Studio, and I'm trying to consume it using the automatically generated proxy class. The Web Service returns a class that I have implemented, containing a List.
Question
The proxy class has automatically generated methods to send the SOAP to the web service. It uses the Invoke() method to execute the call, and then casts the result as a DataSet. How can I get this object back into the class I know it is?
I know that I can hand-edit the auto-generated file, but that's not very maintainable, so I don't want to go down that route (any time the Web Service is rebuilt, the changes would have to be made again).
Is there a way to tell the generated class to be more specific, and actually use the correct data type? Or do I have to write a clunky set of deserialisers to get my data back into the correct shape?
Example
One method in my Web Service class:
[WebMethod]
public UpdateList RetrieveUpdates(long sessionID, string configurationVersion, string coreVersion, string researcherDBVersion)
{ ... }
Adding the class as a Web Reference generates the following proxy method:
public DataSet RetrieveUpdates(long sessionID, string configurationVersion, string coreVersion, string researcherDBVersion) {
object[] results = this.Invoke("RetrieveUpdates", new object[] {
sessionID,
configurationVersion,
coreVersion,
researcherDBVersion});
return ((DataSet)(results[0]));
}
The DataSet I receive from this method is always empty (because you can't cast from my class to a DataSet).
Thanks in advance
Since Web References generate partial classes, you should be able to add to your project a partial class extension to the proxy class that reimplements just the method in question (just copy and paste it) but changes the return type (and the name, of course). If the method signature changes, you'll have to update your extension, but at least if that doesn't happen and you regenerate the proxy you won't have to reapply any changes (and you can still use any other generated classes/methods as is).
I've used this approach before to "fix" proxy classes (for instance, to add SOAP headers that aren't defined in the WSDL), and while not ideal, it does work.
Unless your client code knows about your custom class (e.g. has a reference to the assembly) you will not be able to retrieve an object of that type from the service.
It sounds like what you are looking to do is share types across a service layer. In order to do that you will either have to give your client app a copy of the assembly that has the
UpdateList type or you will need to look at something like WCF.