Delen via


OData-feeds gebruiken vanuit een werkstroom

WCF Data Services is een onderdeel van .NET Framework waarmee u services kunt maken die gebruikmaken van het Open Data Protocol (OData) om gegevens beschikbaar te maken en te gebruiken via het web of intranet met behulp van de semantiek van representational state transfer (REST). OData maakt gegevens beschikbaar als resources die kunnen worden adresseerbaar door URI's. Elke toepassing kan communiceren met een op OData gebaseerde gegevensservice als deze een HTTP-aanvraag kan verzenden en de OData-feed kan verwerken die een gegevensservice retourneert. Daarnaast bevat WCF Data Services clientbibliotheken die een rijkere programmeerervaring bieden wanneer u OData-feeds van .NET Framework-toepassingen gebruikt. Dit onderwerp bevat een overzicht van het gebruik van een OData-feed in een werkstroom met en zonder gebruik van de clientbibliotheken.

De OData-voorbeeldservice Northwind gebruiken

In de voorbeelden in dit onderwerp wordt gebruikgemaakt van de voorbeeldgegevensservice Northwind in https://services.odata.org/Northwind/Northwind.svc/. Deze service wordt geleverd als onderdeel van de OData SDK en biedt alleen-lezentoegang tot de voorbeelddatabase Northwind. Als schrijftoegang gewenst is of als een lokale WCF-gegevensservice gewenst is, kunt u de stappen van de quickstart voor WCF Data Services volgen om een lokale OData-service te maken die toegang biedt tot de Northwind-database. Als u de quickstart volgt, vervangt u de lokale URI door de URI die is opgegeven in de voorbeeldcode in dit onderwerp.

Een OData-feed gebruiken met behulp van de clientbibliotheken

WCF Data Services bevat clientbibliotheken waarmee u eenvoudiger een OData-feed van .NET Framework en clienttoepassingen kunt gebruiken. Deze bibliotheken vereenvoudigen het verzenden en ontvangen van HTTP-berichten. Ze vertalen de nettolading van het bericht ook naar CLR-objecten die entiteitsgegevens vertegenwoordigen. De clientbibliotheken bevatten de twee kernklassen DataServiceContext en DataServiceQuery<TElement>. Met deze klassen kunt u een query uitvoeren op een gegevensservice en vervolgens met de geretourneerde entiteitsgegevens werken als CLR-objecten. In deze sectie worden twee benaderingen beschreven voor het maken van activiteiten die gebruikmaken van de clientbibliotheken.

Een servicereferentie toevoegen aan de WCF-gegevensservice

Als u de Northwind-clientbibliotheken wilt genereren, kunt u het dialoogvenster Servicereferentie toevoegen in Visual Studio 2012 gebruiken om een verwijzing naar de OData-service Northwind toe te voegen.

Schermopname van het dialoogvenster Servicereferentie toevoegen.

Houd er rekening mee dat er geen servicebewerkingen beschikbaar zijn voor de service en dat er in de lijst Services items zijn die de entiteiten vertegenwoordigen die worden weergegeven door de Northwind-gegevensservice. Wanneer de servicereferentie wordt toegevoegd, worden klassen gegenereerd voor deze entiteiten en kunnen ze worden gebruikt in de clientcode. In de voorbeelden in dit onderwerp worden deze klassen en de NorthwindEntities klasse gebruikt om de query's uit te voeren.

Notitie

Zie De Data Service Client Library (WCF Data Services) genereren voor meer informatie.

Asynchrone methoden gebruiken

Als u mogelijke latentieproblemen wilt oplossen die kunnen optreden bij het openen van resources via internet, raden we u aan om asynchroon toegang te krijgen tot WCF Data Services. De WCF Data Services-clientbibliotheken bevatten asynchrone methoden voor het aanroepen van query's en Windows Workflow Foundation (WF) biedt de klasse voor het AsyncCodeActivity ontwerpen van asynchrone activiteiten. AsyncCodeActivity afgeleide activiteiten kunnen worden geschreven om te profiteren van .NET Framework-klassen met asynchrone methoden, of de code die asynchroon moet worden uitgevoerd, kan in een methode worden geplaatst en aangeroepen met behulp van een gemachtigde. In deze sectie vindt u twee voorbeelden van een AsyncCodeActivity afgeleide activiteit: een activiteit die gebruikmaakt van de asynchrone methoden van de WCF Data Services-clientbibliotheken en een die gebruikmaakt van een gemachtigde.

Notitie

Zie Asynchrone bewerkingen (WCF Data Services) en Asynchrone activiteiten maken voor meer informatie.

Gebruik asynchrone methoden van de clientbibliotheek

De DataServiceQuery<TElement> klasse biedt BeginExecute en EndExecute methoden voor het asynchroon opvragen van een OData-service. Deze methoden kunnen worden aangeroepen vanuit de BeginExecute en EndExecute overrides van een AsyncCodeActivity afgeleide klasse. Wanneer de AsyncCodeActivityBeginExecute onderdrukking retourneert, kan de werkstroom inactief gaan (maar niet blijven bestaan), en wanneer het asynchrone werk is voltooid, EndExecute wordt aangeroepen door de runtime.

In het volgende voorbeeld wordt een OrdersByCustomer activiteit gedefinieerd met twee invoerargumenten. Het CustomerId argument vertegenwoordigt de klant die aangeeft welke orders moeten worden geretourneerd en het ServiceUri argument vertegenwoordigt de URI van de OData-service die moet worden opgevraagd. Omdat de activiteit is afgeleid van AsyncCodeActivity<IEnumerable<Order>> er ook een Result uitvoerargument is dat wordt gebruikt om de resultaten van de query te retourneren. Met BeginExecute de overschrijving wordt een LINQ-query gemaakt waarmee alle orders van de opgegeven klant worden geselecteerd. Deze query wordt gespecificeerd als de UserState van de doorgegeven AsyncCodeActivityContext, en vervolgens wordt de BeginExecute-methode van de query aangeroepen. Houd er rekening mee dat de callback en status die aan de query's BeginExecute worden doorgegeven, dezelfde zijn die naar de methode van de activiteit BeginExecute worden doorgegeven. Wanneer de query is uitgevoerd, wordt de EndExecute-methode van de activiteit aangeroepen. De query wordt opgehaald uit de UserState en vervolgens wordt de EndExecute-methode van de query aangeroepen. Met deze methode wordt een IEnumerable<T> van het opgegeven entiteitstype geretourneerd. In dit geval Order. Aangezien IEnumerable<Order> het algemene type is van de AsyncCodeActivity<TResult>, wordt dit IEnumerable ingesteld als de ResultOutArgument<T> van de activiteit.

class OrdersByCustomer : AsyncCodeActivity<IEnumerable<Order>>
{
    [RequiredArgument]
    public InArgument<string> CustomerId { get; set; }

    [RequiredArgument]
    public InArgument<string> ServiceUri { get; set; }

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        NorthwindEntities dataContext = new NorthwindEntities(new Uri(ServiceUri.Get(context)));

        // Define a LINQ query that returns Orders and
        // Order_Details for a specific customer.
        DataServiceQuery<Order> ordersQuery = (DataServiceQuery<Order>)
            from o in dataContext.Orders.Expand("Order_Details")
            where o.Customer.CustomerID == CustomerId.Get(context)
            select o;

        // Specify the query as the UserState for the AsyncCodeActivityContext
        context.UserState = ordersQuery;

        // The callback and state used here are the ones passed into
        // the BeginExecute of this activity.
        return ordersQuery.BeginExecute(callback, state);
    }

    protected override IEnumerable<Order> EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {
        // Get the DataServiceQuery from the context.UserState
        DataServiceQuery<Order> ordersQuery = context.UserState as DataServiceQuery<Order>;

        // Return an IEnumerable of the query results.
        return ordersQuery.EndExecute(result);
    }
}

In het volgende voorbeeld haalt de OrdersByCustomer activiteit een lijst met orders voor de opgegeven klant op, waarna een ForEach<T> activiteit de geretourneerde orders opsommen en de datum van elke order naar de console schrijft.

Variable<IEnumerable<Order>> orders = new Variable<IEnumerable<Order>>();
DelegateInArgument<Order> order = new DelegateInArgument<Order>();

Activity wf = new Sequence
{
    Variables = { orders },
    Activities =
    {
        new WriteLine
        {
            Text = "Calling WCF Data Service..."
        },
        new OrdersByCustomer
        {
            ServiceUri = "http://services.odata.org/Northwind/Northwind.svc/",
            CustomerId = "ALFKI",
            Result = orders
        },
        new ForEach<Order>
        {
            Values = orders,
            Body = new ActivityAction<Order>
            {
                Argument = order,
                Handler = new WriteLine
                {
                    Text = new InArgument<string>((env) => string.Format("{0:d}", order.Get(env).OrderDate))
                }
            }
        }
    }
};

WorkflowInvoker.Invoke(wf);

Wanneer deze werkstroom wordt aangeroepen, worden de volgende gegevens naar de console geschreven:

Calling WCF Data Service...
8/25/1997
10/3/1997
10/13/1997
1/15/1998
3/16/1998
4/9/1998

Notitie

Als er geen verbinding met de OData-server tot stand kan worden gebracht, krijgt u een uitzondering die vergelijkbaar is met de volgende uitzondering:

Niet-verwerkte uitzondering: System.InvalidOperationException: er is een fout opgetreden tijdens het verwerken van deze aanvraag. >--- System.Net.WebException: Kan geen verbinding maken met de externe server ---> System.Net.SocketException: een verbindingspoging is mislukt omdat de verbonden partij na een bepaalde periode niet goed heeft gereageerd of de tot stand gebrachte verbinding is mislukt omdat de verbonden host niet heeft gereageerd.

Als aanvullende verwerking van de gegevens die door de query worden geretourneerd vereist is, kan dit worden uitgevoerd in de overschrijving van EndExecute de activiteit. Zowel BeginExecute als EndExecute worden aangeroepen met behulp van de workflowthread, en alle code in deze overrides wordt niet asynchroon uitgevoerd. Als de aanvullende verwerking uitgebreid of langlopend is, of als de queryresultaten worden gepaginad, moet u rekening houden met de aanpak die wordt besproken in de volgende sectie, waarbij een gemachtigde wordt gebruikt om de query uit te voeren en asynchroon aanvullende verwerking uit te voeren.

Een gemachtigde gebruiken

Naast het aanroepen van de asynchrone methode van een .NET Framework-klasse, kan een AsyncCodeActivity-gebaseerde activiteit ook de asynchrone logica in een van zijn methoden definiëren. Deze methode wordt opgegeven met behulp van een delegate in de overschrijving van BeginExecute de activiteit. Wanneer de methode voltooid is, roept de runtime de overschrijving van EndExecute de activiteit aan. Wanneer u een OData-service aanroept vanuit een werkstroom, kan deze methode worden gebruikt om een query uit te voeren op de service en eventuele aanvullende verwerking te bieden.

In het volgende voorbeeld wordt een ListCustomers activiteit gedefinieerd. Deze activiteit voert een query uit op de voorbeeldgegevensservice van Northwind en retourneert een List<Customer> die alle klanten in de Northwind-database bevat. Het asynchrone werk wordt uitgevoerd door de GetCustomers methode. Met deze methode wordt de service voor alle klanten opgevraagd en vervolgens gekopieerd naar een List<Customer>. Vervolgens wordt gecontroleerd of de resultaten worden gepaginad. Zo ja, dan wordt er een query uitgevoerd op de service voor de volgende pagina met resultaten, wordt deze toegevoegd aan de lijst en wordt verdergegaan totdat alle klantgegevens zijn opgehaald.

Notitie

Voor meer informatie over paginering in WCF Data Services, zie Hoe: Gepagineerde Resultaten Laden (WCF Data Services).

Zodra alle klanten zijn toegevoegd, wordt de lijst geretourneerd. De GetCustomers methode wordt gespecificeerd in de overschrijving van BeginExecute de activiteit. Omdat de methode een retourwaarde heeft, wordt er een Func<string, List<Customer>> gemaakt om de methode op te geven.

Notitie

Als de methode waarmee het asynchrone werk wordt uitgevoerd, geen retourwaarde heeft, wordt er een Action gebruikt in plaats van een Func<TResult>. Zie Asynchrone activiteiten maken voor voorbeelden van het maken van een asynchroon voorbeeld met behulp van beide benaderingen.

Dit Func<TResult> wordt toegewezen aan de UserStateen wordt vervolgens BeginInvoke aangeroepen. Aangezien de methode die moet worden aangeroepen geen toegang heeft tot de omgeving van de activiteit met argumenten, wordt de waarde van het ServiceUri argument doorgegeven als de eerste parameter, samen met de callback en status die zijn doorgegeven aan BeginExecute. Wanneer GetCustomers terugkeert, roept de runtime EndExecute aan. De code in EndExecute haalt de delegate op uit UserState, roept EndInvoke aan en retourneert het resultaat, namelijk de lijst van klanten die door de GetCustomers methode wordt geretourneerd.

class ListCustomers : AsyncCodeActivity<List<Customer>>
{
    [RequiredArgument]
    public InArgument<string> ServiceUri { get; set; }

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        // Create a delegate that references the method that implements
        // the asynchronous work. Assign the delegate to the UserState,
        // invoke the delegate, and return the resulting IAsyncResult.
        Func<string, List<Customer>> GetCustomersDelegate = new Func<string, List<Customer>>(GetCustomers);
        context.UserState = GetCustomersDelegate;
        return GetCustomersDelegate.BeginInvoke(ServiceUri.Get(context), callback, state);
    }

    protected override List<Customer> EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {
        // Get the delegate from the UserState and call EndInvoke
        Func<string, List<Customer>> GetCustomersDelegate = (Func<string, List<Customer>>)context.UserState;
        return (List<Customer>)GetCustomersDelegate.EndInvoke(result);
    }

    List<Customer> GetCustomers(string serviceUri)
    {
        // Get all customers here and add them to a list. This method doesn't have access to the
        // activity's environment of arguments, so the Service Uri is passed in.

        // Create the DataServiceContext using the service URI.
        NorthwindEntities context = new NorthwindEntities(new Uri(serviceUri));

        // Return all customers.
        QueryOperationResponse<Customer> response =
            context.Customers.Execute() as QueryOperationResponse<Customer>;

        // Add them to the list.
        List<Customer> customers = new List<Customer>(response);

        // Is this the complete list or are the results paged?
        DataServiceQueryContinuation<Customer> token;
        while ((token = response.GetContinuation()) != null)
        {
            // Load the next page of results.
            response = context.Execute<Customer>(token) as QueryOperationResponse<Customer>;

            // Add the next page of customers to the list.
            customers.AddRange(response);
        }

        // Return the list of customers
        return customers;
    }
}

In het volgende voorbeeld haalt de ListCustomers activiteit een lijst met klanten op, waarna een ForEach<T> activiteit deze opsommen en de bedrijfsnaam en de naam van de contactpersoon van elke klant naar de console schrijft.

Variable<List<Customer>> customers = new Variable<List<Customer>>();
DelegateInArgument<Customer> customer = new DelegateInArgument<Customer>();

Activity wf = new Sequence
{
    Variables = { customers },
    Activities =
    {
        new WriteLine
        {
            Text = "Calling WCF Data Service..."
        },
        new ListCustomers
        {
            ServiceUri = "http://services.odata.org/Northwind/Northwind.svc/",
            Result = customers
        },
        new ForEach<Customer>
        {
            Values = customers,
            Body = new ActivityAction<Customer>
            {
                Argument = customer,
                Handler = new WriteLine
                {
                    Text = new InArgument<string>((env) => string.Format("{0}, Contact: {1}",
                        customer.Get(env).CompanyName, customer.Get(env).ContactName))
                }
            }
        }
    }
};

WorkflowInvoker.Invoke(wf);

Wanneer deze werkstroom wordt aangeroepen, worden de volgende gegevens naar de console geschreven. Omdat deze query veel klanten retourneert, wordt hier slechts een deel van de uitvoer weergegeven.

Calling WCF Data Service...
Alfreds Futterkiste, Contact: Maria Anders
Ana Trujillo Emparedados y helados, Contact: Ana Trujillo
Antonio Moreno Taquería, Contact: Antonio Moreno
Around the Horn, Contact: Thomas Hardy
Berglunds snabbköp, Contact: Christina Berglund
...

Een OData-feed gebruiken zonder de clientbibliotheken te gebruiken

OData maakt gegevens beschikbaar als resources die kunnen worden adresseerbaar door URI's. Wanneer u de clientbibliotheken gebruikt, worden deze URI's voor u gemaakt, maar hoeft u de clientbibliotheken niet te gebruiken. Indien gewenst kunnen OData-services rechtstreeks worden geopend zonder de clientbibliotheken te gebruiken. Wanneer u de clientbibliotheken niet gebruikt, worden de locatie van de service en de gewenste gegevens opgegeven door de URI en worden de resultaten geretourneerd in het antwoord op de HTTP-aanvraag. Deze onbewerkte gegevens kunnen vervolgens op de gewenste manier worden verwerkt of gemanipuleerd. Een manier om de resultaten van een OData-query op te halen, is door de WebClient klasse te gebruiken. In dit voorbeeld wordt de naam van de contactpersoon opgehaald voor de klant die door de sleutel ALFKI wordt vertegenwoordigd.

string uri = "http://services.odata.org/Northwind/Northwind.svc/Customers('ALFKI')/ContactName";
WebClient client = new WebClient();
string data = client.DownloadString(uri);
Console.WriteLine($"Raw data returned:\n{data}");

Wanneer deze code wordt uitgevoerd, wordt de volgende uitvoer weergegeven in de console:

Raw data returned:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ContactName xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">Maria Anders</ContactName>

In een werkstroom kan de code uit dit voorbeeld worden opgenomen in de Execute overschrijving van een aangepaste activiteit op basis van een CodeActivity activiteit, maar dezelfde functionaliteit kan ook worden bereikt met behulp van de InvokeMethod<TResult> activiteit. Met de InvokeMethod<TResult> activiteit kunnen werkstroomauteurs statische methoden en exemplaarmethoden van een klasse aanroepen en heeft ook de mogelijkheid om de opgegeven methode asynchroon aan te roepen. In het volgende voorbeeld wordt een InvokeMethod<TResult> activiteit geconfigureerd om de DownloadString methode van de WebClient klasse aan te roepen en een lijst met klanten te retourneren.

new InvokeMethod<string>
{
    TargetObject = new InArgument<WebClient>(new VisualBasicValue<WebClient>("New System.Net.WebClient()")),
    MethodName = "DownloadString",
    Parameters =
    {
        new InArgument<string>("http://services.odata.org/Northwind/Northwind.svc/Customers('ALFKI')/Orders")
    },
    Result = data,
    RunAsynchronously = true
},

InvokeMethod<TResult> kan zowel statische als exemplaarmethoden van een klasse aanroepen. Omdat DownloadString dit een instantiemethode van de WebClient klasse is, wordt een nieuw exemplaar van de WebClient klasse opgegeven voor de TargetObjectklasse. DownloadString wordt opgegeven als de MethodNameURI die de query bevat, wordt opgegeven in de Parameters verzameling en de retourwaarde wordt toegewezen aan de Result waarde. De RunAsynchronously waarde is ingesteld op true, wat betekent dat de aanroep van de methode asynchroon wordt uitgevoerd met betrekking tot de werkstroom. In het volgende voorbeeld wordt een werkstroom samengesteld die gebruikmaakt van de InvokeMethod<TResult> activiteit om een query uit te voeren op de voorbeeldgegevensservice Northwind voor een lijst met orders voor een specifieke klant en vervolgens worden de geretourneerde gegevens naar de console geschreven.

Variable<string> data = new Variable<string>();

Activity wf = new Sequence
{
    Variables = { data },
    Activities =
    {
        new WriteLine
        {
            Text = "Calling WCF Data Service..."
        },
        new InvokeMethod<string>
        {
            TargetObject = new InArgument<WebClient>(new VisualBasicValue<WebClient>("New System.Net.WebClient()")),
            MethodName = "DownloadString",
            Parameters =
            {
                new InArgument<string>("http://services.odata.org/Northwind/Northwind.svc/Customers('ALFKI')/Orders")
            },
            Result = data,
            RunAsynchronously = true
        },
        new WriteLine
        {
            Text = new InArgument<string>(env => string.Format("Raw data returned:\n{0}", data.Get(env)))
        }
    }
};

WorkflowInvoker.Invoke(wf);

Wanneer deze werkstroom wordt aangeroepen, wordt de volgende uitvoer weergegeven in de console. Omdat deze query verschillende orders retourneert, wordt hier slechts een deel van de uitvoer weergegeven.

Calling WCF Data Service...
Raw data returned:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>*
<feed
xml:base="http://services.odata.org/Northwind/Northwind.svc/"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom">
<title type="text">Orders\</title>
<id>http://services.odata.org/Northwind/Northwind.svc/Customers('ALFKI')/Orders\</id>
<updated>2010-05-19T19:37:07Z\</updated>
<link rel="self" title="Orders" href="Orders" />
<entry>
<id>http://services.odata.org/Northwind/Northwind.svc/Orders(10643)\</id>
<title type="text">\</title>
<updated>2010-05-19T19:37:07Z\</updated>
<author>
<name />
</author>
<link rel="edit" title="Order" href="Orders(10643)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Customer" type="application/atom+xml;type=entry" title="Customer" href="Orders(10643)/Customer" />
...

Dit voorbeeld bevat een methode die auteurs van werkstroomtoepassingen kunnen gebruiken om de onbewerkte gegevens te gebruiken die worden geretourneerd door een OData-service. Zie Accessing Data Service Resources (WCF Data Services) en OData: URI-conventies voor meer informatie over toegang tot WCF-gegevensservices met URI's.