您的位置:首页 > 移动开发 > Objective-C

Returning Objects from Web Services

2010-03-13 10:10 190 查看
When I work with web services I want things to work the same way as if I were working with a local layer that returns objects, not data. I don't want my code outside of the service to even see the data, just the objects that represent the data. Who doesn't? There are some things to know when it comes to consuming objects returned by a web method and they're not what you might expect on first attempt.
First of all, let's say we have the following Person object. We'll put this in an assembly and use it in the web service.
public class Person
{
public Person() {}

public Person(string firstname, string lastname, DateTime dob)
{
this._fname = firstname;
this._lname = lastname;
this._dob = dob;
}

public string FirstName
{
set { this._fname = value; }
get { return this._fname; }
}

public string LastName
{
set { this._lname = value; }
get { return this._lname; }
}

public DateTime DOB
{
set { this._dob = value; }
get { return this._dob; }
}

public int Age
{
get
{
return DateTime.Now.Year - _dob.Year -
(_dob.Month > DateTime.Now.Month ? 1 :
(_dob.Month != DateTime.Now.Month) ? 0 :
(_dob.Day > DateTime.Now.Day) ? 1 : 0);
}
}

public override string ToString()
{
return string.Format("{0} {1}", _fname, _lname);
}

private string _fname = string.Empty;
private string _lname = string.Empty;
private DateTime _dob = DateTime.MinValue;
}


Nothing fancy, some public properties. Some that just set/get private members, others that do something, such as the property for Age and the ToString() override. Now we'll add a simple web method to a service to return an instance of this object.

[WebMethod]
public Person GetPerson()
{
return new Person("Ryan", "Farley", DateTime.Parse("1/1/1970"));
}


So far so good. Now when you add a web reference for the service and call the GetPerson method things go wrong. There are a couple of typical approaches I see most often when I am asked about this kind of thing. First of all, when you add the web reference, a proxy class is created. You've possibly taken a look at these before. The proxy class allows you to make synchronous or asynchronous calls to the web service without needing to know about any of the SOAP bindings or other stuff that is going on. It allows you to call GetPerson just as if it were a method in a local class in your project. What it also does in our case is create a proxy class for our Person object. However, if you try to use the GetPerson method now things won't go as expected. For example, when we use ToString() it does not return the Person's full name, instead it returns a string indicating the object's type, as if it was not overriden at all. Also, our Age property doesn't even appear to exist at all in the class. Let's take a look at why. If we look at the proxy class created by adding the web reference (by opening the Reference.cs file which is located in the appropriate sub-directory that you'll find in the Web References directory under your project) you'll see not only the proxy class for the web service, but also a proxy class for the Person object. But this Person object is not the same as what we returned from our web service. Here's how the Person proxy class looks.

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/")]
public class Person
{
///
public string FirstName;
///
public string LastName;
///
public System.DateTime DOB;
}


The contract of the object may be the same, but it is definitely not the same object. All of the internal code is missing, nothing more than the public read/write members exist. No good.

So you might think that all we need to do now is add a reference to the same assembly containing the Person object and cast the result to that Person type. Not the case, you'll get an InvalidCastException thrown at you. The web method is returning a Person object as defined in our assembly, so why can't we use it as a Person object referenced from that same assembly? If we think about it, when we looked at the proxy class in the Reference.cs file, it defined the return of the GetPerson method as a Person object as defined in the proxy. So if we try to cast it as our Person object then we are the ones that are using the wrong types according to the proxy class. All makes sense now, right?

It is an easy enough solution to remedy this problem. No reason why we just can't modify the proxy class to return the correct Person object (as defined in our assembly). Open the Reference.cs file again and delete the Person proxy class. Then modify any references to the Person object to reflect the Person object defined in our assembly. The actual reference to the assembly containing the Person object already exsits in the project, so we can simply add the appropriate namespace as a using directive and drive on. Recompile and all is well. You are successfully consuming a Person object from your web service. Cool. Keep in mind that if you update the web reference then your changes to the Reference.cs file will be lost and you'll have to make the changes again. One thing you can do is manually create the proxy class file using the command-line wsdl.exe tool, make the changes to that class, and then add it to the project. Then you're safe from loosing those changes.

Edit

One thing I failed to mention. Even though you are returning a Person object from your web service, and using it as a Person in the client, you are only going to get the values for any public members that the Person class exposes. For example, if you have private members in your class and these private members don't have public read/write accessors, then you won't get those values when you consume the service and use the returned Person object. The reason why this is becomes very apparent when you look at the actual XML return for the GetPerson method in our service. Let's say we add a private member to store the person's Social Security number and we add a writable only setter for this member (let's just say the number is not directly accessed by the client but instead the private memeber is used elsewhere by other public members). When you look at the XML returned by the GetPerson method it will still look like this:



Ryan
Farley
1970-01-01T00:00:00.0000000-07:00


No sign of the value for Social Security number anywhere, so be sure that it will not make it to the client (obviously). If you think about what is happening behind the scenes it all makes sense. The Person object is serialized when returned from the GetPerson method. So you're only going to get the publically accessible values returned. So make sure you keep this in mind when designing your objects so you don't hose yourself when you try to access a value that never made it from the web service.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: