В данном статье рассказывается об ActivityRest. Эта Activity интресна тем, что работает в составе трехзвенной архитектуры, причем работает с использованием технологий REST, WCF, WorkFlow. Происходит это следующим образом, клиентская машина передает запрос на сервер используя технологию WCF, сервер получив запрос, запускает WorkFlow, в состав которого входит ActivityRest, которая обращается за данными, по технологгии REST, находящимися в сети по определенному URI - суть к третьей машине. Считанные данных последовательно пересылаются сначала на сервер клиента, затем с сервера на машину клиента.
Представлен рабочий проект MS Visual Studio 2010 содержащий WCF + WorkFlow + REST + WindowsFormClient, в котором применяется описываемое Activity.
1. Входные данные ActivityRest.
Входные аргументы для Activity собраны в классе InputArgument и состоят из двух полей:
public class InputArgument
{
public string UrlString { get; set; }
public string CustomerID { get; set; }
}
2. Выходные данные ActivityRest.
Для выходных данных не определяется специальный класс. Однако, тип выходных данных опреден в составе Activity. В данном случае это результат Linq запроса - IEnumerable<Order>.
protected override IEnumerable<Order> EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
try
{
3. Исходный текст ActivityRest.
Как обычно, класс реализующий Activity создан асинхронным, содержащим два метода:
- BeginExecute;
- EndExecute.
В данном случае, это более чем обосновано, так как информация запрашивается и передается с одного сервера на другой, используя технологию REST протокола HTTP, так что, неминуемы задержки. Основным элементом ActivityRest является Linq запрос на получение данных, предоставляемых с URI:
http://services.odata.org/Northwind/Northwind.svc/
/* 10.01.2013. Простой Activity. Замечателен тем, что получает от клиента в качестве
входных данных Uri и фильтр для данных. Однако, данные читает не со своего сервера, а обращается
к сервису на третьей машине по полученному Uri: http://services.odata.org/Northwind/Northwind.svc/
Работает асинхронно. Получив данные отправляет их клиенту используя WCF и WorkFlow.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using WorkFlowRest.ServiceReference1;
using System.Data.Services.Client;
using ClassLibrary;
using System.ComponentModel;
namespace WorkFlowRest
{
public sealed class CodeActivityRest : AsyncCodeActivity<IEnumerable<Order>>
{
[RequiredArgument]
[DefaultValue(null)]
public InArgument<InputArgument> inputArguments { get; set; }
NorthwindEntities entityContext = null;
DataServiceQuery<Order> entityQuery = null;
// Temporary variable for input arguments
private InputArgument inputObject = null;
private string uri = null;
private string customerId = null;
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
try
{
// Input Object
inputObject = inputArguments.Get(context);
//Uri for service
uri = inputObject.UrlString;
if (String.IsNullOrEmpty(uri)) throw new ArgumentNullException("Value", "Uri string is Empty");
// Filter for Data
customerId = inputObject.CustomerID;
if (customerId == null) throw new ArgumentNullException("Value", "CustomerID string is null");
// Set EntityContext
entityContext = new NorthwindEntities(new Uri(uri));
// Create entityQuery
entityQuery = (DataServiceQuery<Order>)
from obj in entityContext.Orders
where obj.Customer.CustomerID.Contains(customerId)
select obj;
context.UserState = entityQuery;
return entityQuery.BeginExecute(callback, state);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
return null;
}
}
protected override IEnumerable<Order> EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
try
{
// Get context.UserState
entityQuery = context.UserState as DataServiceQuery<Order>;
// Return entityQuery.
return entityQuery.EndExecute(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
return null;
}
}
}
}
4. Клиент для ActivityRest
Ниже приведен текст
клиента, который формирует и передает URI и фильт данных для ActivityRest в виде строковых полей класса InputArgument.Затем, клиент принимает данные от сервера, и уже на принятых данных, выполняет еще один Linq запрос. Этот запрос выполняет группировку и сортировку данных по полю CustomerID. Результат второго Linq запроса предназначается для компонента ComboBox в качестве источника данных.
/* 10.03.2012. Клиент для AcnivityRest.
Формирует и передает на сервер Uri и фильтр для получения данных.
Отображает полученные данные. Интересен тем, что выполняет Linq запрос на
полученном ранее результате запроса (первый запрос в ActivityRect).
Этот второй Linq запрос используется для
группировки данных с целью формирования DataSource для ComboBox.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WindowsFormsClient.ServiceReference2;
using ClassLibrary;
namespace WindowsFormsClient
{
public partial class FormClient : Form
{
// Link for Service Client
ServiceClient client = null;
// Input Class
private ClassLibrary.InputArgument input = null;
public FormClient()
{
InitializeComponent();
// Create Objects and set parameters
client = new ServiceClient();
input = new InputArgument();
input.CustomerID = string.Empty;
input.UrlString = @"http://services.odata.org/Northwind/Northwind.svc/";
}
// Event click button for clean filter
private void button1_Click(object sender, EventArgs e)
{
// Empty Filter comboBox1
comboBox1.Text = "";
input.CustomerID = string.Empty;
//Call Form1_Load
FormClient_Load(sender, e);
}
// Load Data
private void FormClient_Load(object sender, EventArgs e)
{
try
{
// Send and Get Data
var order = client.GetData(input);
// Too Query
var groupCustomerID = from row in order
// orderby row.CustomerID ascending
group row by row.CustomerID into grouping
orderby grouping.Key ascending
select grouping.Key;
foreach (var item in groupCustomerID) comboBox1.Items.Add(item.ToString());
// Exception is order == null
if (order == null) { throw new ArgumentNullException("Value", "Order is null"); }
// Set DataSource
dataGridView1.DataSource = order;
label3.Text = order.Count<Order>().ToString();
}
catch (Exception ex)
{
MessageBox.Show(" Error: " + ex.ToString());
}
}
// Change CustomerID in ComboBox
private void comboBox1_TextChanged(object sender, EventArgs e)
{
try
{
input.CustomerID = (string)comboBox1.SelectedItem;
// Send and Get Data
var order = client.GetData(input);
// Exception
if (order == null) { throw new ArgumentNullException("Value", "Order is null"); }
// Set DataSource
dataGridView1.DataSource = order;
label3.Text = order.Count<Order>().ToString();
}
catch (Exception ex)
{
MessageBox.Show(" Error: " + ex.ToString());
}
}
}
}
Visual Studio 2010 проект содержащий: Activity, Workflow, Windows Form клиент можно
загрузить.
Евгений Вересов.
10.01.2013 года.