Web service design, implementetion and testing
Sluzba s protokolem SOAP je dostupna na
zde .
Sluzba s protokolem REST je dostupna na
zde
Design
Pro realizaci webove sluzby jsem se rozhodli pouzit Windows Communication Foundation (WCF).
WCF je framework zamerujici se na service oriented communication, ktery umoznuje vzajemnou komunikaci sluzeb pres ruzna rozhrani, at jiz SOAP, P2P a radu dalsich.
Abychom si vyzkoušeli obě technologie pro srovnání, implementovali jsme jednu službu s protokolem SOAP a jednu s REST.
Obě webové služby implementují perzistenci přes session. Tj. funguje zde klasický webový model - přihášení → práce → odhlášení.
Pokud uživatel není přihlášen, nebo není v roli, která má pro danou metodu práva, není mu umožněno tuto metodu použít.
Application layers
Implementation
SOAP Service
Poskytovane metody
LogIn
LogOut
GetAllUsers
GetAllProjects
GetAllProjects
GetTasksInProject
GetTaskById - READ
AddTask - CREATE
UpdateTask - UPADTE
CloseTask - DELETE
AddAnswer
GetTaskAnswers
GetUserById
Service contract
[ServiceContract]
public interface ITaskManagerService
{
[OperationContract]
string LogIn(string login, string password);
[OperationContract]
void LogOut();
[OperationContract]
DataUser[] GetAllUsers();
[OperationContract]
DataProject[] GetAllProjects();
[OperationContract]
DataTask[] GetTasksInProject(int projectId);
[OperationContract]
DataTask GetTaskById(int id);
[OperationContract]
DataTask AddTask(int projectId, string name, int priorityId, string description, DateTime deadline, List<int> usersIds);
[OperationContract]
DataTask UpdateTask(int taskId, string name, int priorityId, string description, DateTime deadline,
List<int> userIds, int stateId);
[OperationContract]
void CloseTask(int taskId);
[OperationContract]
void AddAnswer(int taskId, string name, string text);
[OperationContract]
DataAnswer[] GetTaskAnswers(int taskId);
[OperationContract]
DataUser GetUserById(int id);
}
Testing
Pro testovani jsme pouzili
WcfTestClient, ktery je soucasti WCF Development Tools a umoznuje uplne testovani webove sluzby pomoci UI.
Ukazka komunikace
Request
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/ITaskManagerService/GetTaskById</Action>
</s:Header>
<s:Body>
<GetTaskById xmlns="http://tempuri.org/">
<id>6</id>
</GetTaskById>
</s:Body>
Response
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<GetTaskByIdResponse xmlns="http://tempuri.org/">
<GetTaskByIdResult xmlns:a="http://schemas.datacontract.org/2004/07/TaskManager.TaskManagerService.DataTypes" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Description>dsadsdasd</a:Description>
<a:ID>6</a:ID>
<a:Name>Task2</a:Name>
<a:PriorityId>3</a:PriorityId>
<a:ProjectId>3</a:ProjectId>
<a:UsersIds i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
</GetTaskByIdResult>
</GetTaskByIdResponse>
</s:Body>
</s:Envelope>
REST service
Poskytovane metody
LogIn
LogOut
GetMyInfo
GetAllProjects
GetTasksInProject - READ
CreateProject - CREATE
CloseTask - UPDATE
Service contract
/// <summary>
/// Verifies specified credentials and logs the user into the system if valid.
/// </summary>
/// <param name="login">The login.</param>
/// <param name="password">The password.</param>
/// <param name="err">The error object.</param>
/// <returns>
/// Returns true if the specified credentials are valid and the login process was successfull.
/// Returns false otherwise.
/// If an error occurs, the err param is filled with the error info.
/// </returns>
[OperationContract]
[WebGet(UriTemplate = "/LogIn/{login}/{password}", BodyStyle = WebMessageBodyStyle.WrappedResponse)]
bool LogIn(string login, string password, out ErrorInfo err);
/// <summary>
/// Logs the current user out of the application. New LogIn will be required to proceed with any other operations.
/// </summary>
[OperationContract]
[WebGet(UriTemplate = "/LogOut")]
void LogOut();
/// <summary>
/// Gets information about currently logged user.
/// </summary>
/// <param name="err">The error object.</param>
/// <returns>
/// Returns new DataUser object with information about the current user.
/// If an error occurs, the err param is filled with the error info.
/// </returns>
[OperationContract]
[WebGet(UriTemplate = "/GetMyInfo", BodyStyle = WebMessageBodyStyle.WrappedResponse)]
DataUser GetMyInfo(out ErrorInfo err);
/// <summary>
/// Gets a list of all projects.
/// </summary>
/// <returns>List of DataProject objects representing all Projects in the application.</returns>
[OperationContract]
[WebGet(UriTemplate = "/GetAllProjects")]
List<DataProject> GetAllProjects();
/// <summary>
/// Creates a new project.
/// </summary>
/// <param name="name">The name of the project.</param>
/// <returns>Returns a newly created instance of DataProject.</returns>
[OperationContract]
[WebGet(UriTemplate = "/CreateProject/{name}")]
DataProject CreateProject(string name);
/// <summary>
/// Gets all tasks in project with specified id.
/// </summary>
/// <param name="id">The id of the project to get the tasks for.</param>
/// <returns>List of DataTask objects representing all tasks in the project with specified id.</returns>
[OperationContract]
[WebGet(UriTemplate = "/GetTasksInProject/{id}")]
List<DataTask> GetTasksInProject(string id);
/// <summary>
/// Sets the state of taks with the specified id to closed.
/// </summary>
/// <param name="taskId">The task id.</param>
/// <returns>Newly updated DataTask object.</returns>
[OperationContract]
[WebGet(UriTemplate = "/CloseTask/{taskId}")]
DataTask CloseTask(string taskId);
Testing
Ukázka komunikace
Request
GET http://taskmanager.borovicka.name/Services/TMRESTService.svc/GetTasksInProject/1
Response
<arrayofdatatask xmlns="http://schemas.datacontract.org/2004/07/TaskManager.TaskManagerService.DataTypes" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<datatask>
<description>desca55</description>
<id>5</id>
<name>Task number 5!!!</name>
<priorityid>1</priorityid>
<projectid>1</projectid>
<usersids i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"></usersids>
</datatask>
<datatask>
<description>sdsdsd</description>
<id>9</id>
<name>asdsddfdf</name>
<priorityid>1</priorityid>
<projectid>1</projectid>
<usersids i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"></usersids>
</datatask>
<datatask>
<description>joooxx</description>
<id>10</id>
<name>super task2</name>
<priorityid>1</priorityid>
<projectid>1</projectid>
<usersids i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"></usersids>
</datatask>
<datatask>
<description>pop</description>
<id>11</id>
<name>popop</name>
<priorityid>1</priorityid>
<projectid>1</projectid>
<usersids i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"></usersids>
</datatask>
<datatask>
<description>vvvv</description>
<id>12</id>
<name>aaa</name>
<priorityid>1</priorityid>
<projectid>1</projectid>
<usersids i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"></usersids>
</datatask>
</arrayofdatatask>