retrieveMultipleRecords (referència de l'API del client)

Recupera una col·lecció de registres de taula.

Sintaxi

Xrm.WebApi.retrieveMultipleRecords(entityLogicalName, options, maxPageSize).then(successCallback, errorCallback);

Paràmetres

Nom Tipus Necessari Descripció
entityLogicalName String Sí Nom lògic de la taula dels registres que voleu recuperar. Per exemple: account.
options String No Opcions de consulta del sistema OData o consulta FetchXML per recuperar les dades. Veure opcions
maxPageSize Nombre No Especifica un nombre positiu que indiqui el nombre de registres de taula a retornar per pàgina. Si no especifiques aquest paràmetre, el valor per defecte és el límit màxim de 5.000 registres per a taules estàndard i 500 per a taules elàstiques.

Si el nombre de registres que recuperes és superior al valor especificat maxPageSize o al límit màxim per al tipus de taula, la nextLink columna de l'objecte de promissió retornada conté un enllaç per recuperar els registres.
successCallback Function No Funció per cridar quan es recuperen registres de taula. Vegeu el valor retornat
errorCallback Function No Una funció per cridar quan l'operació falla. Es passa un objecte amb les propietats següents:
- errorCode:Número. El codi d'error com a nombre decimal positiu. Per exemple, el codi d'error documentat com es 0x80040333 retornarà com 2147746611a .
- message:Corda. Un missatge d'error que descriu el problema.

Opcions

S'admeten les opcions de consulta del sistema següents: $select, $top, $filter, $expandi $orderby.

Utilitzeu l'opció de $expand consulta del sistema per controlar quines dades de les taules relacionades es retornen. Si només incloeu el nom de la propietat de navegació, rebreu totes les propietats dels registres relacionats. Pots limitar les propietats retornades per als registres relacionats utilitzant l'opció $select de consulta del sistema entre parèntesis després del nom de la propietat de navegació. Utilitza aquesta opció tant per a propietats de navegació d'un sol valor com per a la col·lecció . Per a fora de línia, només s'admet l'opció anidada $select dins del lloc $expand .

Per especificar una consulta FetchXML, utilitzeu la fetchXml columna per especificar la consulta.

Nota

Sempre has d'utilitzar l'opció $select de consulta del sistema per limitar les propietats retornades d'un registre de taula incloent una llista separada per coma dels noms de propietats. Aquesta pràctica és important per al rendiment. Si no especifiques propietats utilitzant $select, totes les propietats es retornen.

Especifica les opcions de consulta que comencen per ?. També podeu especificar diverses opcions de consulta del sistema utilitzant & per separar les opcions de consulta.

Quan especifiquis una cadena de consulta OData per al options paràmetre, codifica la consulta per a caràcters especials.

Quan especifiquis una consulta FetchXML per al options paràmetre, no codifiquis la consulta.

Per aprendre a definir el options paràmetre per a diversos escenaris de recuperació múltiple, vegeu Exemples.

Valor retornat

En cas d'èxit, retorna un objecte de promesa a la successCallback amb les propietats següents:

Nom Tipus Descripció
entities Matriu d'objectes JSON Cada objecte representa el registre de taula recuperat que conté columnes i els seus valors com key: value a parells. L'ID del registre de la taula es recupera per defecte.
nextLink String (opcional) Si el nombre de registres que s'estan recuperant és superior al valor especificat al maxPageSize paràmetre de la sol·licitud, es retorna l'adreça URL per retornar la pàgina següent de registres.
fetchXmlPagingCookie (opcional) Per a una operació basada en retrieveMultipleRecords fetchXML amb paginació on el recompte total de registres és més gran que el valor de paginació, aquest atribut retorna la galeta de paginació que es pot utilitzar per a una operació fetchXml posterior per recuperar la pàgina següent de registres.

Tipus d'atributs no compatibles per a les opcions de consulta d'OData en mòbil fora de línia

Els següents tipus de columna no són compatibles quan s'utilitzen Xrm.WebApi.retrieveMultipleRecords opcions de cadena de consulta d'OData (com $select i $filter) en mode mòbil fora de línia. Utilitza FetchXML si necessites treballar amb un tipus d'atribut en aquesta llista de tipus d'atributs no suportats.

  • MultiSelectPicklist
  • File
  • Image
  • ManagedProperty
  • CalendarRules
  • PartyList
  • Virtual

Funcions no compatibles en mòbils fora de línia

Les següents funcions no són compatibles en mòbils fora de línia:

  • Característiques d'agrupació i agregació

Operacions de filtre suportades per tipus d'atribut en mòbil fora de línia utilitzant FetchXML

Les operacions següents són compatibles per a tots els tipus d'atributs quan es treballa amb FetchXML:

  • Igual a (eq)
  • No és igual (neq)
  • Nul (null)
  • No nul (not-null)

A la taula següent es mostren més operacions admeses per a cada tipus d'atribut:

Tipus d'atribut Operacions admeses
BigInt, decimal, doble, enter Major que (gt)
Major o igual a (gte)
Menor que (lt)
Menor o igual a (lte)
Booleà, Client A (in)
No a (not-in)
EntityName, Llista de selecció, Estat, Estat M'agrada (like)
No com (not-like)
Comença per (begins-with)
No comença per (not-begin-with)
Acaba amb (ends-with)
No acaba amb (not-end-with)
A (in)
No a (not-in)
Guid, Cerca A (in)
No a (not-in)
És igual a ID d'usuari (eq-userid)
No és igual a ID d'usuari (ne-userid)
Money Major que (gt)
Major o igual a (gte)
Menor que (lt)
Menor o igual a (lte)
A (in)
No a (not-in)
Propietari A (in)
No a (not-in)
És igual a ID d'usuari (eq-userid)
No és igual a ID d'usuari (ne-userid)
És igual a usuari o equip (eq-useroruserteams)
String M'agrada (like)
No com (not-like)
Comença per (begins-with)
No comença per (not-begin-with)
Acaba amb (ends-with)
No acaba amb (not-end-with)
DataHora El O Després (on-or-after)
Activat (on)
El o abans (on-or-before)
Avui (today)
Demà (tomorrow)
Ahir (yesterday)
Propers set dies (next-seven-days)
Darrers set dies (last-seven-days)
La setmana vinent (next-week)
La setmana passada (last-week)
Aquesta setmana (this-week)
El mes següent (next-month)
Darrer mes (last-month)
Aquest mes (this-month)
L'any vinent (next-year)
L'any passat (last-year)
Aquest any (this-year)
Darrers X dies (last-x-days)
Propers X dies (next-x-days)
Últimes X setmanes (last-x-weeks)
Properes X setmanes (next-x-weeks)
Darrers X mesos (last-x-months)
Propers X mesos (next-x-months)
Darrers X anys (last-x-years)
Propers X anys (next-x-years)
Major que (gt)
Major o igual (gte)
Menor que (lt)
Menor o igual (lte)

Exemples

Pots utilitzar el mètode retrieveMultipleRecords per aconseguir la majoria dels escenaris i exemples esmentats a Query Data utilitzant l'API web. Alguns dels exemples es llisten a la secció següent.

Recuperació bàsica de múltiples

En aquest exemple es consulta el conjunt de taules de comptes i s'utilitzen les $select opcions de consulta i $top del sistema per retornar la propietat name dels tres primers comptes:

Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name&$top=3").then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }                    
        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Recuperació bàsica de múltiples amb FetchXML

Aquest exemple consulta l'entitat account mitjançant fetchXML.

var fetchXml = "?fetchXml=<fetch><entity name='account'><attribute name='accountid'/><attribute name='name'/></entity></fetch>";

Xrm.WebApi.retrieveMultipleRecords("account", fetchXml).then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }                    

        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Recuperar o filtrar per propietats de cerca

Per a la majoria de propietats de navegació d'un sol valor, es troba una propietat calculada de només lectura que utilitza la següent convenció de nomenclatura: _<name>_value on el <name> és el nom de la propietat de navegació d'un sol valor. Per a finalitats de filtratge, també pots utilitzar el valor específic de la propietat de navegació d'un sol valor. Tanmateix, aquestes opcions de sintaxi no són compatibles amb clients mòbils en mode fora de línia. Utilitza el nom de propietat de navegació d'un sol valor tant per a la recuperació com per al filtratge. A més, el mode fora de línia no suporta la comparació de propietats de navegació amb null.

Més informació: Propietats de cerca

Aquí tens exemples de codi per a ambdós escenaris:

Per a l'escenari en línia (connectat al servidor)

En aquest exemple es consulta el conjunt de taules comptes i s'utilitzen les opcions de consulta i $select del $filter sistema per retornar el nom i la propietat primarycontactid per als comptes que tenen un contacte principal concret:

Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name,_primarycontactid_value&$filter=primarycontactid/contactid eq a0dbf27c-8efb-e511-80d2-00155db07c77").then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }                    
        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Per a l'escenari Mobile Offline

Aquest exemple consulta el conjunt de taules de comptes i utilitza les $select opcions de consulta del sistema $filter i per retornar la propietat name i primarycontactid per als comptes que tenen un contacte primari concret quan treballen en mode fora de línia:

Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name,primarycontactid&$filter=primarycontactid eq a0dbf27c-8efb-e511-80d2-00155db07c77").then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }                    
        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Ús de FetchXML per recuperar o filtrar per propietats de cerca (escenari en línia i fora de línia)

Utilitza el FetchXML paràmetre tant en línia com fora de línia per recuperar la name propietat i primarycontactid dels registres de comptes que tinguin un contacte principal que coincideixi amb una condició:

var fetchXml = `?fetchXml=
    <fetch>
       <entity name='account'>
          <attribute name='name'/>
          <attribute name='primarycontactid'/>
          <link-entity name='contact' from='contactid' to='primarycontactid'>
             <filter type='and'>
                <condition attribute='lastname' operator='eq' value='Contoso'/>
             </filter>
          </link-entity>
       </entity>
    </fetch>`;

Xrm.WebApi.retrieveMultipleRecords("account", fetchXml).then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }                    

        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Especifiqueu el nombre de taules que s'han de retornar en una pàgina

L'exemple següent mostra com utilitzar el maxPageSize paràmetre per especificar que cada pàgina mostra tres registres.

Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name", 3).then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }
        console.log("Next page link: " + result.nextLink);
        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Aquest exemple mostra tres registres i un enllaç a la pàgina següent. Aquí teniu un exemple de sortida de la consola a les eines de desenvolupament del navegador:

{@odata.etag: "W/"1035541"", name: "A. Datum", accountid: "475b158c-541c-e511-80d3-3863bb347ba8"}
@odata.etag: "W/"1035541""accountid: "475b158c-541c-e511-80d3-3863bb347ba8"name: "A. Datum"__proto__: Object
VM5595:4 
{@odata.etag: "W/"947306"", name: "Adventure Works", accountid: "a8a19cdd-88df-e311-b8e5-6c3be5a8b200"}
VM5595:4 
{@odata.etag: "W/"1033754"", name: "Alpine Ski House", accountid: "aaa19cdd-88df-e311-b8e5-6c3be5a8b200"}
VM5595:6 
Next page link: [Organization URI]/api/data/v9.0/accounts?$select=name&$skiptoken=%3Ccookie%20pagenumber=%222%22%20pagingcookie=%22%253ccookie%2520page%253d%25221%2522%253e%253caccountid%2520last%253d%2522%257bAAA19CDD-88DF-E311-B8E5-6C3BE5A8B200%257d%2522%2520first%253d%2522%257b475B158C-541C-E511-80D3-3863BB347BA8%257d%2522%2520%252f%253e%253c%252fcookie%253e%22%20istracking=%22False%22%20/%3E

Utilitza la part de consulta a l'URL de la nextLink propietat com a valor del options paràmetre en la teva propera crida retrieveMultipleRecords per sol·licitar el següent conjunt de registres. No canviïs ni afegeixis més opcions de consulta del sistema al valor. Per a cada petició posterior de més pàgines, utilitza el mateix maxPageSize valor que vas utilitzar a la petició original de recuperar múltiples. També, emmagatzema en memòria cau els resultats retornats o el valor de la nextLink propietat perquè la teva aplicació pugui retornar les pàgines recuperades prèviament.

Per exemple, per obtenir la següent pàgina de registres, passa la part de consulta de l'URL nextLink al options paràmetre:

Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name&$skiptoken=%3Ccookie%20pagenumber=%222%22%20pagingcookie=%22%253ccookie%2520page%253d%25221%2522%253e%253caccountid%2520last%253d%2522%257bAAA19CDD-88DF-E311-B8E5-6C3BE5A8B200%257d%2522%2520first%253d%2522%257b475B158C-541C-E511-80D3-3863BB347BA8%257d%2522%2520%252f%253e%253c%252fcookie%253e%22%20istracking=%22False%22%20/%3E", 3).then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }
        console.log("Next page link: " + result.nextLink);
        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Aquesta petició retorna la següent pàgina del conjunt de resultats.

{@odata.etag: "W/"1035542"", name: "Blue Yonder Airlines", accountid: "aca19cdd-88df-e311-b8e5-6c3be5a8b200"}
VM5597:4 
{@odata.etag: "W/"1031348"", name: "City Power & Light", accountid: "aea19cdd-88df-e311-b8e5-6c3be5a8b200"}
VM5597:4 
{@odata.etag: "W/"1035543"", name: "Coho Winery", accountid: "b0a19cdd-88df-e311-b8e5-6c3be5a8b200"}
VM5597:6 
Next page link: [Organization URI]/api/data/v9.0/accounts?$select=name&$skiptoken=%3Ccookie%20pagenumber=%223%22%20pagingcookie=%22%253ccookie%2520page%253d%25222%2522%253e%253caccountid%2520last%253d%2522%257bB0A19CDD-88DF-E311-B8E5-6C3BE5A8B200%257d%2522%2520first%253d%2522%257bACA19CDD-88DF-E311-B8E5-6C3BE5A8B200%257d%2522%2520%252f%253e%253c%252fcookie%253e%22%20istracking=%22False%22%20/%3E

Important

El valor de la nextLink propietat està codificat per URI. Si codifiquis el valor per URI abans d'enviar-lo, la informació de les galetes XML a l'URL provoca un error.

Exemple de FetchXML (escenari en línia)

L'exemple següent mostra com utilitzar el count paràmetre de FetchXML per especificar que cada pàgina mostra tres registres.

Nota

La galeta de paginació FetchXML només es retorna per a operacions en línia retrieveMultipleRecords . (Xrm.WebApi.online). No està admès fora de línia.

var fetchXml = "?fetchXml=<fetch count='3'><entity name='account'><attribute name='accountid'/><attribute name='name'/></entity></fetch>";

Xrm.WebApi.online.retrieveMultipleRecords("account", fetchXml).then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }          

        console.log("Paging cookie: " + result.fetchXmlPagingCookie);

        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Aquest exemple mostra tres registres i retorna una galeta de paginació FetchXML per recuperar els resultats de la pàgina següent si hi ha més registres al conjunt de resultats. Aquí teniu un exemple de sortida de la consola a les eines de desenvolupament del navegador:

{
   "entities": [
      {
         "@odata.etag": "W/\"1035542\"",
         "accountid": "aca19cdd-88df-e311-b8e5-6c3be5a8b200",
         "name": "Blue Yonder Airlines"
      },
      {
         "@odata.etag": "W/\"1031348\"",
         "accountid": "aea19cdd-88df-e311-b8e5-6c3be5a8b200",
         "name": "City Power & Light"
      },
      {
         "@odata.etag": "W/\"1035543\"",
         "accountid": "b0a19cdd-88df-e311-b8e5-6c3be5a8b200",
         "name": "Coho Winery"
      }
   ],
   "fetchXmlPagingCookie": "<cookie pagenumber=\"2\" pagingcookie=\"%253ccookie%2520page%253d%25221%2522%253e%253caccountid%2520last%253d%2522%257b0748C6EC-55A8-EB11-B1B5-000D3AFEF6FA%257d%2522%2520first%253d%2522%257bFC47C6EC-55A8-EB11-B1B5-000D3AFEF6FA%257d%2522%2520%252f%253e%253c%252fcookie%253e\" istracking=\"False\" />"
}

Per obtenir grans conjunts de resultats amb paginació, utilitzeu el fetchXmlPagingCookie que es mostra en l'exemple següent.

function CreateXml(fetchXml, pagingCookie, page, count) {
  var domParser = new DOMParser();
  var xmlSerializer = new XMLSerializer();

  var fetchXmlDocument = domParser.parseFromString(fetchXml, "text/xml");

  if (page) {
    fetchXmlDocument
      .getElementsByTagName("fetch")[0]
      .setAttribute("page", page.toString());
  }

  if (count) {
    fetchXmlDocument
      .getElementsByTagName("fetch")[0]
      .setAttribute("count", count.toString());
  }

  if (pagingCookie) {
    var cookieDoc = domParser.parseFromString(pagingCookie, "text/xml");
    var innerPagingCookie = domParser.parseFromString(
      decodeURIComponent(
        decodeURIComponent(
          cookieDoc
            .getElementsByTagName("cookie")[0]
            .getAttribute("pagingcookie")
        )
      ),
      "text/xml"
    );
    fetchXmlDocument
      .getElementsByTagName("fetch")[0]
      .setAttribute(
        "paging-cookie",
        xmlSerializer.serializeToString(innerPagingCookie)
      );
  }

  return xmlSerializer.serializeToString(fetchXmlDocument);
}

function retrieveAllRecords(entityName, fetchXml, page, count, pagingCookie) {
  if (!page) {
    page = 0;
  }

  return retrievePage(entityName, fetchXml, page + 1, count, pagingCookie).then(
    function success(pageResults) {
      if (pageResults.fetchXmlPagingCookie) {
        return retrieveAllRecords(
          entityName,
          fetchXml,
          page + 1,
          count,
          pageResults.fetchXmlPagingCookie
        ).then(
          function success(results) {
            if (results) {
              return pageResults.entities.concat(results);
            }
          },
          function error(e) {
            throw e;
          }
        );
      } else {
        return pageResults.entities;
      }
    },
    function error(e) {
      throw e;
    }
  );
}

function retrievePage(entityName, fetchXml, pageNumber, count, pagingCookie) {
  var fetchXml =
    "?fetchXml=" + CreateXml(fetchXml, pagingCookie, pageNumber, count);

  return Xrm.WebApi.online.retrieveMultipleRecords(entityName, fetchXml).then(
    function success(result) {
      return result;
    },
    function error(e) {
      throw e;
    }
  );
}

var count = 3;
var fetchXml =
  '<fetch><entity name="account"><attribute name="accountid"/><attribute name="name"/></entity></fetch>';

retrieveAllRecords("account", fetchXml, null, count, null).then(
  function success(result) {
    console.log(result);

    // perform additional operations on retrieved records
  },
  function error(error) {
    console.log(error.message);
    // handle error conditions
  }
);

Utilitza l'opció de consulta del sistema $expand a les propietats de navegació per controlar les dades que retornen de les taules relacionades. L'exemple següent mostra com recuperar el contacte de tots els registres del compte. Per als registres de contacte relacionats, només es recuperen els contactid camps i:fullname

Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name&$top=3&$expand=primarycontactid($select=contactid,fullname)", 3).then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }        
        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

El codi anterior retorna un resultat amb un esquema com:

{
   "entities": [
      {
         "@odata.etag": "W/\"1459919\"",
         "name": "Test Account",
         "accountid": "119edfac-19c6-ea11-a81a-000d3af5e732",
         "primarycontactid": {
            "contactid": "6c63a1b7-19c6-ea11-a81a-000d3af5e732",
            "fullname": "Test Contact"
         }
      }
   ]
}

Nota

De manera similar a l'escenari en línia, utilitzeu l'opció de consulta del sistema $expand per recuperar dades de taules relacionades fora de línia. Tanmateix, les relacions de molts a molts no estan suportades fora de línia.

Mètode obsolet per a l'escenari Mobile Offline

Nota

El @odata.nextLink està obsolet per a escenaris Mobile Offline. Tot i que encara és compatible amb personalitzacions existents, ja no l'utilitzis.

Una operació de $expand fora de línia retorna una @odata.nextLink anotació que conté informació sobre com accedir a la informació del registre relacionat. Utilitza els idparàmetres , entityType, i options d'aquesta anotació per construir una o més peticions addicionals Xrm.WebApi.offline.retrieveRecord . El codi següent proporciona un exemple complet de com fer-ho:

Xrm.WebApi.offline.retrieveMultipleRecords("account", "?$select=name&$top=3&$expand=primarycontactid($select=contactid,fullname)").then(function(resultSet) {
    /**
     *  resultSet has a structure like:
     *  {
     *      "entities": [
     *          {
     *              "accountid": "119edfac-19c6-ea11-a81a-000d3af5e732",
     *              "name": "Test Account",
     *              "primarycontactid@odata.nextLink": {
     *                  "API": "{Xrm.Mobile.offline}.{retrieveRecord}",
     *                  "id": "119edfac-19c6-ea11-a81a-000d3af5e732",
     *                  "entityType": "account",
     *                  "options": "?$select=accountid&$expand=primarycontactid($select=contactid,fullname)&$getOnlyRelatedEntity=true"
     *              },
     *              "primarycontactid": {}
     *          }
     *      ]
     *  }
     *
     *  Notice the empty `primarycontactid` property but an additional `primarycontactid@odata.nextLink` 
     *  annotation that lets us know how to get to the linked data that we need.
     **/

    var promises = resultSet.entities.map(function(outerItem) {
        // We do a retrieveRecord() for every item in the result set of retrieveMultipleRecords() and then
        // combine the results into the retrieveMultipleRecords() result set itself.
       return Xrm.WebApi.offline.retrieveRecord(
           outerItem["primarycontactid@odata.nextLink"].entityType, 
           outerItem["primarycontactid@odata.nextLink"].id,
           outerItem["primarycontactid@odata.nextLink"].options
        ).then(function(innerResult) {            
            if (innerResult.value.length === 0) {
                return outerItem;
            }
            outerItem.primarycontactid = innerResult.value[0];
            return outerItem;
        });
    });

    return Promise.all(promises);
}).then(function(allResults) {
    for (var i = 0; i < allResults.length; i++) {
        console.log(allResults[i]);
    }
    // perform additional operations on retrieved records
}, function(error) {
    console.error(error);
    // handle error conditions
});

Per a més exemples de recuperació de múltiples registres utilitzant Web API, vegeu Consulta Dades utilitzant l'API Web.

Consulta de dades mitjançant l'API web
Xrm.WebApi.retrieveRecord
Xrm.WebApi