샘플: 여러 요청 실행
게시 날짜: 2017년 1월
적용 대상: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online
네트워크를 통해 많은 수의 개별 조직 메시지 요청을 보내면 대량 데이터 가져오기 작업과 마찬가지로 네트워크 성능에 영향을 받습니다. 성능 향상을 위해 Microsoft Dynamics 365(온라인 및 온-프레미스)은 요청을 단일 웹 서비스 메서드 호출로 일괄 처리할 수 있습니다.
이 샘플 코드는 Microsoft Dynamics 365(온라인 및 온-프레미스)용입니다.Microsoft Dynamics CRM SDK 패키지를 다운로드합니다. 다운로드 패키지의 다음 위치에서 확인할 수 있습니다.
SampleCode\CS\DataManagement\ExecuteMultiple\ExecuteMultiple.cs
요구 사항
이 SDK에서 제공된 샘플 코드를 실행하기 위한 요구 사항에 대한 자세한 내용은 샘플 및 도우미 코드 사용을 참조하십시오.
보여 주기
이 샘플에서는 ExecuteMultipleRequest를 매개 변수로 전달하여 여러 조직 메시지 요청을 단일 웹 서비스 메서드 호출로 실행하는 방법을 보여 줍니다. 네트워크를 통해 전송되어야 하는 메시지 요청 수를 줄이면 메시지 처리 성능이 향상됩니다. 샘플의 주요 섹션만 표시하는 조각이 먼저 표시되고, 그 뒤에 전체 샘플 코드가 표시됩니다.
예제
이 샘플에서는 단일 웹 메서드 호출을 사용하여 컬렉션의 모든 메시지 요청을 실행합니다. 실행 동작을 변경하는 설정도 표시됩니다.
// Get a reference to the organization service.
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri,serverConfig.Credentials, serverConfig.DeviceCredentials))
{
// Enable early-bound type support to add/update entity records required for this sample.
_serviceProxy.EnableProxyTypes();
#region Execute Multiple with Results
// Create an ExecuteMultipleRequest object.
requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
// Create several (local, in memory) entities in a collection.
EntityCollection input = GetCollectionOfEntitiesToCreate();
// Add a CreateRequest for each entity to the request collection.
foreach (var entity in input.Entities)
{
CreateRequest createRequest = new CreateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
}
// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
// Display the results returned in the responses.
foreach (var responseItem in responseWithResults.Responses)
{
// A valid response.
if (responseItem.Response != null)
DisplayResponse(requestWithResults.Requests[responseItem.RequestIndex], responseItem.Response);
// An error has occurred.
else if (responseItem.Fault != null)
DisplayFault(requestWithResults.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
전체 샘플 코드
using System;
using System.ServiceModel;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Query;
using System.Collections.Generic;
namespace Microsoft.Crm.Sdk.Samples
{
public class ExecuteMultiple
{
#region Class Level Members
private OrganizationServiceProxy _serviceProxy;
private readonly List<Guid> _newAccountIds = new List<Guid>();
#endregion
#region How To Sample Code
/// <summary>
/// This sample demonstrates how to execute a collection of message requests using a single web service
/// call and optionally return the results.
/// </summary>
/// <seealso cref="https://msdn.microsoft.com/en-us/library/gg328075.aspx"/>
/// <param name="serverConfig">Contains server connection information.</param>
/// <param name="promptforDelete">When True, the user will be prompted to delete all
/// created entities.</param>
public void Run(ServerConnection.Configuration serverConfig, bool promptforDelete)
{
ExecuteMultipleRequest requestWithResults = null;
try
{
// Get a reference to the organization service.
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri,serverConfig.Credentials, serverConfig.DeviceCredentials))
{
// Enable early-bound type support to add/update entity records required for this sample.
_serviceProxy.EnableProxyTypes();
#region Execute Multiple with Results
// Create an ExecuteMultipleRequest object.
requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
// Create several (local, in memory) entities in a collection.
EntityCollection input = GetCollectionOfEntitiesToCreate();
// Add a CreateRequest for each entity to the request collection.
foreach (var entity in input.Entities)
{
CreateRequest createRequest = new CreateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
}
// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
// Display the results returned in the responses.
foreach (var responseItem in responseWithResults.Responses)
{
// A valid response.
if (responseItem.Response != null)
DisplayResponse(requestWithResults.Requests[responseItem.RequestIndex], responseItem.Response);
// An error has occurred.
else if (responseItem.Fault != null)
DisplayFault(requestWithResults.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
#endregion Execute Multiple with Results
#region Execute Multiple with No Results
ExecuteMultipleRequest requestWithNoResults = new ExecuteMultipleRequest()
{
// Set the execution behavior to not continue after the first error is received
// and to not return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = false
},
Requests = new OrganizationRequestCollection()
};
// Update the entities that were previously created.
EntityCollection update = GetCollectionOfEntitiesToUpdate();
foreach (var entity in update.Entities)
{
UpdateRequest updateRequest = new UpdateRequest { Target = entity };
requestWithNoResults.Requests.Add(updateRequest);
}
ExecuteMultipleResponse responseWithNoResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithNoResults);
// There should be no responses unless there was an error. Only the first error
// should be returned. That is the behavior defined in the settings.
if (responseWithNoResults.Responses.Count > 0)
{
foreach (var responseItem in responseWithNoResults.Responses)
{
if (responseItem.Fault != null)
DisplayFault(requestWithNoResults.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
}
else
{
Console.WriteLine("All account records have been updated successfully.");
}
#endregion Execute Multiple with No Results
#region Execute Multiple with Continue On Error
ExecuteMultipleRequest requestWithContinueOnError = new ExecuteMultipleRequest()
{
// Set the execution behavior to continue on an error and not return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = true,
ReturnResponses = false
},
Requests = new OrganizationRequestCollection()
};
// Update the entities but introduce some bad attribute values so we get errors.
EntityCollection updateWithErrors = GetCollectionOfEntitiesToUpdateWithErrors();
foreach (var entity in updateWithErrors.Entities)
{
UpdateRequest updateRequest = new UpdateRequest { Target = entity };
requestWithContinueOnError.Requests.Add(updateRequest);
}
ExecuteMultipleResponse responseWithContinueOnError =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithContinueOnError);
// There should be no responses except for those that contain an error.
if (responseWithContinueOnError.Responses.Count > 0)
{
if (responseWithContinueOnError.Responses.Count < requestWithContinueOnError.Requests.Count)
{
Console.WriteLine("Response collection contain a mix of successful response objects and errors.");
}
foreach (var responseItem in responseWithContinueOnError.Responses)
{
if (responseItem.Fault != null)
DisplayFault(requestWithContinueOnError.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
}
else
{
// No errors means all transactions are successful.
Console.WriteLine("All account records have been updated successfully.");
}
#endregion Execute Multiple with Continue On Error
DeleteRequiredRecords(promptforDelete);
}
}
catch (FaultException<OrganizationServiceFault> fault)
{
// Check if the maximum batch size has been exceeded. The maximum batch size is only included in the fault if it
// the input request collection count exceeds the maximum batch size.
if (fault.Detail.ErrorDetails.Contains("MaxBatchSize"))
{
int maxBatchSize = Convert.ToInt32(fault.Detail.ErrorDetails["MaxBatchSize"]);
if (maxBatchSize < requestWithResults.Requests.Count)
{
// Here you could reduce the size of your request collection and re-submit the ExecuteMultiple request.
// For this sample, that only issues a few requests per batch, we will just print out some info. However,
// this code will never be executed because the default max batch size is 1000.
Console.WriteLine("The input request collection contains %0 requests, which exceeds the maximum allowed (%1)",
requestWithResults.Requests.Count, maxBatchSize);
}
}
// Re-throw so Main() can process the fault.
throw;
}
}
#region Public Methods
/// <summary>
/// Deletes any entity records that were created for this sample.
/// <param name="prompt">Indicates whether to prompt the user
/// to delete the records created in this sample.</param>
/// </summary>
public void DeleteRequiredRecords(bool prompt)
{
bool deleteRecords = true;
if (prompt)
{
Console.WriteLine("\nDo you want to delete the account record? (y/n) [y]: ");
String answer = Console.ReadLine();
deleteRecords = (answer.StartsWith("y") || answer.StartsWith("Y") || answer == String.Empty);
}
if (!deleteRecords)
return;
ExecuteMultipleRequest requestWithNoResults = new ExecuteMultipleRequest()
{
// Set the execution behavior to not continue after the first error is received
// and to not return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = false
},
Requests = new OrganizationRequestCollection()
};
// Update the entities that were previously created.
EntityCollection delete = GetCollectionOfEntitiesToDelete();
foreach (var entity in delete.Entities)
{
DeleteRequest deleteRequest = new DeleteRequest { Target = entity.ToEntityReference() };
requestWithNoResults.Requests.Add(deleteRequest);
}
ExecuteMultipleResponse responseWithNoResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithNoResults);
// There should be no responses unless there was an error. Only the first error
// should be returned. That is the behavior defined in the settings.
if (responseWithNoResults.Responses.Count > 0)
{
foreach (var responseItem in responseWithNoResults.Responses)
{
if (responseItem.Fault != null)
DisplayFault(requestWithNoResults.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
}
else
{
Console.WriteLine("All account records have been deleted successfully.");
}
}
#endregion
#region Private Methods
/// <summary>
/// Create a collection of entity objects for updating. Give these entities a new
/// name for the update. However, use a bad (empty) GUID in some entities to demonstrate
/// returning errors in ExecuteMultipleResponse.
/// </summary>
/// <returns>An entity collection.</returns>
private EntityCollection GetCollectionOfEntitiesToUpdateWithErrors()
{
EntityCollection collection = new EntityCollection()
{
EntityName = Account.EntityLogicalName
};
for (int i = 1; i <= _newAccountIds.Count; i++)
{
if (i % 2 > 0)
{
collection.Entities.Add(
new Account
{
Name = "Again Updated Example Account " + i.ToString(),
Id = new Guid()
});
}
else
{
collection.Entities.Add(
new Account
{
Name = "Again Updated Example Account " + i.ToString(),
Id = _newAccountIds[i - 1]
});
}
}
return collection;
}
/// <summary>
/// Create a collection of entity objects for updating. Give these entities a new
/// name for the update.
/// </summary>
/// <returns>An entity collection.</returns>
private EntityCollection GetCollectionOfEntitiesToUpdate()
{
EntityCollection collection = new EntityCollection()
{
EntityName = Account.EntityLogicalName
};
for (int i = 1; i <= _newAccountIds.Count; i++)
{
collection.Entities.Add(
new Account
{
Name = "Updated Example Account " + i.ToString(),
Id = _newAccountIds[i - 1]
});
}
return collection;
}
/// <summary>
/// Create a collection of new entity objects.
/// </summary>
/// <returns>A collection of entity objects.</returns>
private EntityCollection GetCollectionOfEntitiesToCreate()
{
return new EntityCollection()
{
EntityName = Account.EntityLogicalName,
Entities = {
new Account { Name = "Example Account 1" },
new Account { Name = "Example Account 2" },
new Account { Name = "Example Account 3" },
new Account { Name = "Example Account 4" },
new Account { Name = "Example Account 5" }
}
};
}
/// <summary>
/// Delete a collection of entity objects.
/// </summary>
/// <returns>A collection of entity objects</returns>
private EntityCollection GetCollectionOfEntitiesToDelete()
{
EntityCollection collection = new EntityCollection()
{
EntityName = Account.EntityLogicalName
};
for (int i = 1; i <= _newAccountIds.Count; i++)
{
collection.Entities.Add(
new Account
{
Id = _newAccountIds[i - 1]
});
}
return collection;
}
/// <summary>
/// Display the response of an organization message request.
/// </summary>
/// <param name="organizationRequest">The organization message request.</param>
/// <param name="organizationResponse">The organization message response.</param>
private void DisplayResponse(OrganizationRequest organizationRequest, OrganizationResponse organizationResponse)
{
Console.WriteLine("Created " + ((Account)organizationRequest.Parameters["Target"]).Name
+ " with account id as " + organizationResponse.Results["id"].ToString());
_newAccountIds.Add(new Guid(organizationResponse.Results["id"].ToString()));
}
/// <summary>
/// Display the fault that resulted from processing an organization message request.
/// </summary>
/// <param name="organizationRequest">The organization message request.</param>
/// <param name="count">nth request number from ExecuteMultiple request</param>
/// <param name="organizationServiceFault">A WCF fault.</param>
private void DisplayFault(OrganizationRequest organizationRequest, int count,
OrganizationServiceFault organizationServiceFault)
{
Console.WriteLine("A fault occurred when processing {1} request, at index {0} in the request collection with a fault message: {2}", count + 1,
organizationRequest.RequestName,
organizationServiceFault.Message);
}
#endregion
#endregion How To Sample Code
#region Main method
/// <summary>
/// Standard Main() method used by most SDK samples.
/// </summary>
/// <param name="args"></param>
static public void Main(string[] args)
{
try
{
// Obtain the target organization's Web address and client logon
// credentials from the user.
ServerConnection serverConnect = new ServerConnection();
ServerConnection.Configuration config = serverConnect.GetServerConfiguration();
var app = new ExecuteMultiple();
app.Run(config, true);
}
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp);
Console.WriteLine("Code: {0}", ex.Detail.ErrorCode);
Console.WriteLine("Message: {0}", ex.Detail.Message);
Console.WriteLine("Trace: {0}", ex.Detail.TraceText);
Console.WriteLine("Inner Fault: {0}",
null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
}
catch (System.TimeoutException ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Message: {0}", ex.Message);
Console.WriteLine("Stack Trace: {0}", ex.StackTrace);
Console.WriteLine("Inner Fault: {0}",
null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message);
}
catch (System.Exception ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine(ex.Message);
// Display the details of the inner exception.
if (ex.InnerException != null)
{
Console.WriteLine(ex.InnerException.Message);
FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe = ex.InnerException
as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>;
if (fe != null)
{
Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp);
Console.WriteLine("Code: {0}", fe.Detail.ErrorCode);
Console.WriteLine("Message: {0}", fe.Detail.Message);
Console.WriteLine("Trace: {0}", fe.Detail.TraceText);
Console.WriteLine("Inner Fault: {0}",
null == fe.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
}
}
}
// Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException,
// SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException.
finally
{
Console.WriteLine("Press <Enter> to exit.");
Console.ReadLine();
}
}
#endregion Main method
}
}
참고 항목
ExecuteMultipleRequest
ExecuteMultipleSettings
조직 서비스를 사용하여 데이터 또는 메타데이터 읽고 씁니다.
ExecuteMultiple을 사용하여 대량 데이터 로드 성능 향상
Microsoft Dynamics 365
© 2017 Microsoft. All rights reserved. 저작권 정보