How do I stop a setter being exposed over web services? - c#

I want to have an class like this,
public class Apple
{
public string Size { get; set;}
public string Colour { get; set;}
public string Shape { get; set;}
public int appleId { get; set;}
}
I want to expose that over web services using some web methods like this,
public void AddApple(Apple apple)
{
}
public Apple GetApple(int appleId)
{
}
So when I add a service reference in visual studio to that webservice I get client proxy objects generated for me allowing me to create an Apple on the client side and send that through to the webservice.
Is there a way for me to make one of those properties read only on the client side? I need the setters there so that I can set the values on the server side, but I want to control which data they can update on the client side.
Any ideas?
What I could do is pass in some of the data in the constructor, and only expose getters on the ones I want to be read only, but I want to use an object mapper on the server side. That means ideally I would want to leave the setters there.

In general, you cannot assume control over proxies generated at client side. So correct way would be to ignore values sent by client (or raise exception if he changes those values). The service documentation has to be explicitly mention such things.
Edit:
Yet another work-around would be to divide your data class into two classes - one non-editable by client (say Apple1) and another editable - say Apple2. So now service update method can only accept Apple2 so that client can know looking at generated proxy code what he can change. On server side, you can have Apple1 inherited from Apple2 to have complete data but I believe that proxy generated at client will/can anyway have two different unrelated classes. Perhaps better way in such case would be to have composite full AppleFull containing Apple1 and Apple2.

Please refer to the following question and its answers, I just skimmed through your question but I believe that it is a simillar problem as I faced -
WCF serialization and Value object pattern in Domain Driven Design

Another way to achieve that would be to share the assembly containing the Apple class (but no server side component) between server and client. Make the setters internal and mark the server side assemblies as friends using the InternalsVisibleTo attribute.
This will allow the server to use the setters but not the client.

Related

How to share data between Service Project (WCF) and another project

(Edited) -> I have a solution with different projects. It has a strange structure because I'm not an professional software engineer. The solution has three parts: one HMI project (WPF), bussiness project (class library type) and service project (WCF).
In the bussiness project, I do some process that has result which I save in a static class. This results are exposed in the screen by WPF project mentioned previously and now I need to transfer this data by one service placed in the WCF project.
The object is similar to:
[DataContract]
public class ObjectToTransfer
{
[DataMember]
public string ParameterOne = string.Empty;
[DataMember]
public string ParameterTwo = string.Empty;
}
In the other hand, the method that picks up the informtion from static class belonging to bussiness project is like this:
[ServiceBehavior]
public class Service: IService
{
public ObjectToTransfer SendObject()
{
return new ObjectToTransfer{
ParameterOne = BusinessProject.StaticClass.ResultOne,
ParameterTwo = BusinessProject.StaticClass.ResultTwo
};
}
Well, when I consume the service the result is a object with the parameters one and two empty. In additon, when I debug the solution with both projects run, the static class hasn't info in her atributes... It's like whether both projects run independently, in spite of both are under the same solutions..., It's like whether there was no relationship between them. Where is the mistake?
Thank you in advance!
The main thing you will need to do is change the DataContract class to a class with proper getters and setters.
[DataContract]
public class ObjectToTransfer
{
[DataMember]
public string ParameterOne { get; set; }
[DataMember]
public string ParameterTwo { get; set; }
}
The reason this is important is because of the way WCF works when it try to serialize the data from the server to the client. Essentially, the class on the server side schematically matches a generated class on the client. (They share the same class schema.) If there is no proper structure to the class, the data cannot get set. The members are basically read-only.
What you have in your class right now are public member variables, and they are set to always return string.Empty. WCF can't work with that, it is too strict. The server and the client need to be able to read and write to all DataMember properties, so you need the { get; set; }.
Don't forget to refresh your service reference after making this change.
If you need some good resources to learn WCF, check out these videos WCF Tutorial. They are a little dated, but all of the concepts still apply.
This might be late and I am new to WCF service, so I am sharing based on what I have done in my case to share data among different projects.
Background of my project:
I have a WCF service(host), a client and a server project. (A total of 3 different projects.) I will perform the necessary calculation in WCF service. Afterwards, I am suppose to share the result to the client and server. Therefore, there is this variable, variableA, that I have share among the 3 projects.
What I did:
In WCF service, I declare variableA and mark it static:
private **static** string variableA;
Only after I marked variableA as static, then I can see the same variableA across different projects.
I am not sure if this helps but this is what I did in my case.

WCF Service with Windows Foundation

After some looking around, I'm getting the feeling that this approach isn't the best one for the issue I'm trying to resolve, but figured I'd have one last attempt at trying to find a resolution here before I move on to a new approach.
I have the current service layout below and I am trying to achieve the following:
Initial request will have a value in the query string and then the rest of the data will be sent up inside a HTML form post application/x-www-form-urlencode
The CsvLookup will extract information from the posted form data, carry out some processing on it and then return a JSON formatted response to the calling client
The goal with using WF is that, once we have written the activities, we can simply swap out the CsvLookup activity for an SQL DB lookup or something else later on down the line without needed to change any code on the server, the data we receive on this service will always be in the same format and will always be expected to be sent back in the same format as well, it is the intermediary stuff we're hoping to address with this approach
As you can see above, at the moment I have all the variables declared individually within this service and inside the activity I have them declared as such.
public InArgument<string> AccessEmail { get; set; }
public InArgument<Guid> PackageId { get; set; }
public InArgument<string> OwnerEmail { get; set; }
public InArgument<string> Ip { get; set; }
public OutArgument<string> Response { get; set; }
My question is hopefully a fairly straight forward on; Is it possible to assign a service variable to accept a form encoded post of data, or do all the variables need to be assigned individually?
Currently when using WcfTestTool, when I connect to the service, I see all the variables listed one after the other for me to declare, really, I want to declare one value for the query string and another for the main form data.
After some digging around, I've discovered that by default, this sort of setup is primarily geared towards SOAP calls, so to get the kind of functionality I'm looking for, it seems like it's a better idea to use a standard WCF service and then control the functionality within a config file.

WCF service with data contract accessing issue

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.

DisplayAttribute name property not working in Silverlight

I am binding DataGrid.ItemsSource property to the List<PersonDetails> object. I am getting datas through Silverlight-enabled WCF Service. So the PersonDetails class is implemented in Web Project. Each DataGrid's header text is changing as i want if the class is located in Silverlight project. But then I can not use this class in the web service. The only solution is to add same class in to the both of the projects. But, is there any other way?
The class looks like that:
[DataContract]
public class PersonGeneralDetails
{
// Properties
[DataMember]
[DisplayAttribute(Name = "Sira")]
public int RowNumber { get; set; }
[DataMember]
[DisplayAttribute(Name = "Seriyasi")]
public string SerialNumber { get; set; }
}
It seems attributes aren't generated in web project. I know that I can change header text using DataGrid events. But i want to make it work using attributes.
The problem is the WCF DataContract is an inter-operable mechanism that can be used across languages and platforms.
If you take a look to serialized data generated by the DataContractSerializer (or its code in System.Runtime.Serialization.dll, specifically InternalWriteObjectXyz() methods) you'll see that it merely serializes values into a simple XML message. Nothing related to .NET Framework will be there so all kind of attributes, both custom and compiler generated, will be stripped out and won't even received by the client.
It works creating a copy of your data and sending them from server to client, clients will then create a new class with the same signature. Note: a NEW CLASS with the same signature, NOT JUST A NEW OBJECT of the original class.
Of course there are some workaround for this. You may write your own serializer (see this post on SO for an example) or your own ISerializationSurrogate.
If you can deploy/share your assemblies to your clients you have a nice workaround: just deploy them and DataContractSerializer will build the right object on your clients (exactly the same one you had on the server, with all its attributes). Just remember that:
If custom attributes comes from run-time values (for example because of localization) then they'll be resolved on the client, not on the server (because attributes will be created on the client, their values won't be included in the XML message).
In the client application you need to add a reference to the assembly that contains your types.
When you add your service reference you have to instruct VS to use them (or it'll create proxies), in the Service Reference Settings dialog select Reuse types in referenced assemblies (you can limit this to only assemblies you want to share).

How to use XmlAttributeOverrides with WCF

I have a WCF service using basicHttpBinding. On a service method I have a class that is returned, for this class I need to dynamically / programmatically exclude properties and change property names for the XML. This needs to be done both in the WSDL and when the service method is called.
I have searched for the best solution and it seems that I will need to (1) use the XmlAttributeOverrides with the XmlSerializer or (2) implement the IXmlSerializable on the class that needs to be customized. Or there may be a better solution altogether. I know that Property Name + "Specified" can be added to the class and then those properties can be excluded. However, this does not exclude in the WSDL and this doesn't solve the property renaming issue.
Why do I want this? Because of globalization and customization of our application. There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
After MUCH research I the best option is to swap out the WCF serializer with my own custom serializer. However, I never found good examples of how to do this for a custom class that would use the XmlSerializer. Also I'm not sure how I would pass in the XmlAttributeOverrides for a specific class.
Also, this might not be the case for others who want this same functionality but in my application I only need to initialize the values once for the lifetime of the app. Too bad C# doesn't allow static readonly variables to be used with attributes.
Here is an simple example of a class:
public Customer
{
public string Address1
{
get;
set;
}
public string Address2
{
get;
set;
}
public string Zipcode
{
get;
set;
}
}
In this example I would like to for certain installations of the application use PostalCode instead of Zipcode and hide the Address2 property.
Your help is very much appreciated.
Thanks,
Tyler
There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
A standard approach is to create a special Data Transfer Object (DTO). Or several.
I know this seems like a bit of a cop out, but since your object property names are dynamic why not just use property bagging instead of doing this XMLSerializer shuffle?

Categories

Resources