Уеб услуги с asp. Net


Прехвърляне на типове (marshalling)



страница8/9
Дата24.03.2017
Размер0.86 Mb.
#17693
1   2   3   4   5   6   7   8   9

Прехвърляне на типове (marshalling)


Прехвърлянето на типове (маршализация) е процесът на трансформация на различните типове данни от SOAP и XML към .NET типове и обратното. На всеки .NET тип се съпоставя съответен SOAP тип и обратното – на всеки SOAP тип, описан в WSDL дефиницията на услугата, се съпоставя .NET тип. Прехвърлянето на типовете има и своите особености, с които трябва да се съобразяваме.

Не всички .NET типове могат да се прехвър­лят през уеб услуга. Например няма как да прехвърлим на отдалечена машина отворен файл. Някои по-сложни типове, например рекурсивните структури от данни, също не могат да се прехвърлят директно, защото SOAP и WSDL стандартите са по-общи и не са съобразени с всички особености на .NET типовете.

Различни типове данни могат да се предават като параметри на уеб метод и да се връщат като резултат. Когато някакъв тип данни, обект или метод се подаде като SOAP заявка или отговор, той автоматично се прехвърля във вид на XML.

Тъй като всеки език за програмиране може да използва SOAP, SOAP дефинира свои собствени типове данни. Когато се подадат някакви данни в SOAP съобщение, те се прехвърлят в техен SOAP еквивалент. Това позволява на различните езици с различни имена на типовете да комуни­кират ефективно. Фактът, че уеб услугите са базирани на XML сериали­зация, позволява значителен брой типове данни да бъдат прехвърляни (вж. темата "Сериализация на данни" [TODO: link]).


Примитивни типове


Стандартните примитивни типове се прехвърлят директно и безпроблем­но. Това са типовете: string, char, byte, bool, sbyte, int, uint, long, ulong, short, ushort, float, double, decimal. Без проблеми се прехвърлят и някои стандартни структури, като Guid и DateTime. Напри­мер символният низ "Hello World" се прехвърля във вида:

Hello World

Числовите типове също се прехвърлят в текстов вид в строго определен от XML Schema (XSD) спецификацията формат.

­Изброени типове


Всички изброени типове се прехвърлят под формата на низове като се вземат имената на изброените им стойности: enum Color {Red, Blue}.

Класове и структури


От класовете и структурите се само публичните полета и свойства. Поддържат се вложени типове и дървовидни структури, но не и циклични типове. Задължително условие за да може да се прехвърли един клас е той да има дефиниран конструктор без параметри. Ето няколко примера за структури и класове, които се прехвърлят безпроблемно:

public struct Point

{

public int x, y;



}
public class Student

{

public int Age



{

get {…}


set {…}

}

}



Тези типове се прехвърлят във вид на XML по следния начин:


5

5



13



Въпреки, че горните методи не дефинират изрично конструктор без пара­метри, той се дефинира по подразбиране от компилатора, тъй като тези типове не дефинират нито един друг конструктор (вж. темата "Обектно-ориентирано програмиране в .NET [TODO: link]".

Масиви

Масивите от примитивни типове, изброени типове, класове или структури също се прехвърлят без проблеми: string[], Color[], Point[]. За пример можем да разгледаме следният масив от символни низове:



string[] emailAddresses = new string[] {

"testEmail1@testDomain.com",

"testEmail2@testDomain.com"};


Той се прехвърля при пренасяне в SOAP съобщения в следния формат:

SOAP-ENC:arrayType="xsd:string[2]">



testEmail1@testDomain.com





testEmail2@testDomain.com






Колекции


Колекциите от примитивни типове, изброени типове, класове или струк­тури се прехвърлят като масиви. Това означава, че ако даден уеб метод връща колекция (например ArrayList), в WSDL описанието вместо колек­ция типът ще бъде дефиниран като масив. В резултат на това и в междин­ния (proxy) клас методът ще връща масив. За пример можем да разгле­даме извикването на следния уеб метод:

[WebMethod]

public ArrayList HelloWorld()

{

ArrayList list = new ArrayList();



list.Add("item 1");

list.Add("item 2");

list.Add(42);

return list;

}


При извикването на този метод резултатът се прехвърля във вид на XML в следния формат:



item 1

item 2

42


DataSet обекти


DataSet обектите също могат да се предават през уеб услуги. Тяхното представяне е доста обемисто и затова трябва да се внимава, тъй като те значително увеличават обема на информация, прехвърляна между услу­гата и приложенията. При прехвърляне на DataSet обект се прехвърля XSD схемата му, последвана от сериализираните данни за всяка от таблиците му под формата на XML.

XmlNode


Всякакви XML фрагменти могат да се предават между клиента и услугата в чист вид. В .NET Framework тези XML фрагменти съответстват на класа System.Xml.XmlNode.

Прехвърляне на типовете – пример


За да демонстрираме прехвърлянето на типове между клиент и уеб услуга, ще създадем примерна уеб услуга TypesService с няколко уеб метода. По описания по-рано начин, създаваме първо услугата, а след това и помощен клас, структура и енумерация:

public enum Color

{

Red,



Blue

};
public struct Point

{

public int x, y;



}
public class Student

{

// Private fields - not serialized and marshalled



private string mName;

private int mAge;

private int mState = 0;
public string Name

{

get



{

return mName;

}

set


{

mName = value;

}

}
public int Age



{

get


{

return mAge;

}

set


{

mAge = value;

}

}
// This parameterless public constructor



// is required for the XML serialization

public Student()

{

}
public Student(string aName, int aAge)



{

mName = aName;

mAge = aAge;

}

}



Добавяме следните уеб методи:

GetColors() – връща масив от тип Color. Ще върне елементите на избро­ения тип Color:

[WebMethod(Description="Returns a list of available colors.")]

public Color[] GetColors()

{

Color[] colors = new Color[2];



colors[0] = Color.Blue;

colors[1] = Color.Red;


return colors;

}


CalculateDistance(…) – приема като параметър две променливи от тип Point и връща като резултат разстоянието между двете точки в Евклидово пространство:

[WebMethod(Description="Calculates distance between two points in the plane.")]

public double CalculateDistance(Point p1, Point p2)

{

int dx = p1.x - p2.x;



int dy = p1.y - p2.y;

double distance = Math.Sqrt(dx*dx + dy*dy);

return distance;

}


ConvertDegreesToRadians(…) – приема променлива от тип double, пред­ставляваща големината на ъгъл в градуси и връща стойността му в радиани в същата променлива. На практика променливата е входно-изходна. Такива променливи се поддържат стандартно от уеб услугите:

[WebMethod(Description="Converts given angle from degrees to radians.")]

public void ConvertDegreesToRadians(ref double aAngle)

{

aAngle = (double) aAngle * Math.PI / 180;



}

GetStudents() – връща примерен масив от обекти от тип Student:

[WebMethod(Description="Returns a list of Student objects.")]

public Student[] GetStudents()

{

Student[] students = new Student[3];



students[0] = new Student("Иван", 20);

students[1] = new Student("Мария", 19);

students[2] = new Student("Жоро", 21);

return students;

}


GetDataSet() – създава примерен DataSet и го връща като резултат:

[WebMethod(Description="Returns a DataSet with the tables Towns and Countries.")]

public DataSet GetDataSet()

{

DataTable towns = new DataTable("Towns");



towns.Columns.Add("id", typeof(int));

towns.Columns.Add("name", typeof(string));

DataRow sofia = towns.NewRow();

sofia["id"] = 1;

sofia["name"] = "София";

towns.Rows.Add(sofia);

DataRow varna = towns.NewRow();

varna["id"] = 2;

varna["name"] = "Варна";

towns.Rows.Add(varna);


DataTable countries = new DataTable("Countries");

countries.Columns.Add("id", typeof(int));

countries.Columns.Add("name", typeof(string));
DataRow bg = countries.NewRow();

bg["id"] = 1;

bg["name"] = "България";

countries.Rows.Add(bg);


DataSet ds = new DataSet();

ds.Tables.Add(towns);

ds.Tables.Add(countries);

return ds;

}


SlowCalculation() – приспива нишката на изпълнение на метода за да симулира времеотнемащо изпълнение. Ще използваме този метод по-нататък, когато разглеждаме асинхронните извиквания:

[WebMethod(Description="Simultes a slow calculation.")]

public int SlowCalculation()

{

System.Threading.Thread.Sleep(3000);



return 0;

}


Ако компилираме сега уеб услугата и я заредим през браузъра ще видим списъка от методи, които са на разположение да бъдат извикани и крат­кото описание зададено в полето Description на атрибута WebMethod за всеки от тях:

Можем да извикваме методите, за да тестваме услугата през уеб браузъра или можем да използваме специално написан за услугата клиент:



static void Main()

{

MyServices.TypesService service =



new MyServices.TypesService();
// Invoke GetColors() web method

MyServices.Color[] colors = service.GetColors();

Console.WriteLine("Colors:");

foreach (MyServices.Color color in colors)

{

Console.WriteLine(color);



}
// Invoke CalculateDistance() web method

MyServices.Point p1 = new MyServices.Point();

p1.x = 4;

p1.y = 5;

MyServices.Point p2 = new MyServices.Point();

p2.x = 7;

p2.y = -3;

double distance = service.CalculateDistance(p1,p2);

Console.WriteLine("\nDistance = {0}", distance);
// Invoke ConvertDegreesToRadians(double angle)

double angle = 90;

service.ConvertDegreesToRadians(ref angle);

Console.WriteLine("\nAngle in radians = {0}", angle);


// Invoke GetStudents()

MyServices.Student[] students = service.GetStudents();

Console.WriteLine("\nStudents:");

foreach (MyServices.Student student in students)

{

Console.WriteLine("{0} : {1}", student.Name, student.Age);



}
// Invoke GetDataSet()

DataSet ds = service.GetDataSet();


DataTable towns = ds.Tables["Towns"];

Console.WriteLine("\nTowns:");

foreach (DataRow town in towns.Rows)

{

Console.WriteLine("{0} : {1}", town["id"], town["name"]);



}

DataTable countries = ds.Tables["Countries"];

Console.WriteLine("\nCountries:");

foreach (DataRow country in countries.Rows)

{

Console.WriteLine("{0} : {1}",



country["id"], country["name"]);

}

}



Горният клиент разчита на типовете от пространството MyServices, които се генерират автоматично от VS.NET по WSDL описанието на услугата. Тези типове съответстват на оригиналните .NET типове, дефинирани в услу­гата, но реално са локални класове, структури и енумерации, дефинирани в междинните (proxy) класове на клиента.

Ето и как изглежда резултатът от изпълнението на горния примерен клиентски код:







Сподели с приятели:
1   2   3   4   5   6   7   8   9




©obuch.info 2024
отнасят до администрацията

    Начална страница