CrmService
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.ServiceModel.Description;
using System.Threading;
using System.Web;
using Adacta.Porsche.CallCenter.Web.Helpers;
using Adacta.Porsche.CallCenter.Web.Services.Interfaces;
using Adacta.Porsche.CallCenter.Web.Config;
using AutoMapper;
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;
namespace Adacta.Porsche.CallCenter.Web.Services
{
public interface ICrmService : IDisposable
{
Guid CallerId { get; set; }
Guid? CurrentUserId { get; set; }
// Gets (retrieve one by Id)
Entity Get(string entityLogicalName, Guid entityId, ColumnSet columns);
T Get<T>(Guid entityId) where T : Entity;
// Retrieves (one or many with filters)
Entity Single(string entityLogicalName, string attribute, object value, ColumnSet columns);
T Single<T>(string attribute, object value) where T : Entity;
IList<Entity> Retrieve(string entityLogicalName, string attribute, object value, ColumnSet columns);
IList<T> Retrieve<T>(string attribute, object value) where T : Entity;
IList<Entity> Retrieve(string entityLogicalName, FilterExpression filter, ColumnSet columns);
IList<T> Retrieve<T>(FilterExpression filter) where T : Entity;
IList<Entity> Retrieve(QueryBase query);
IList<T> Retrieve<T>(QueryBase query) where T : Entity;
// Retrieve all
IList<Entity> Retrieve(string entityLogicalName, ColumnSet columns);
IList<T> Retrieve<T>() where T : Entity;
// FetchXML
IList<Entity> Fetch(string fetchXml);
IList<T> Fetch<T>(string fetchXml) where T : Entity;
IList<Entity> Fetch(string fetchXml, out int totalRecordCount);
IList<T> Fetch<T>(string fetchXml, out int totalRecordCount);
// Creates
Guid Create(Entity entity);
Guid Create<T>(T entity) where T : Entity;
// Updates
void Update(Entity entity);
void Update<T>(T entity) where T : Entity;
// Deletes
void Delete(string entityLogicalName, Guid entityId);
void Delete<T>(T entity) where T : Entity;
// Execute
OrganizationResponse Execute(OrganizationRequest request);
// Misc
string RetrieveOptionSetLabel(string entityName, string attribute, int value);
void ChangeState(string entityName, Guid entityId, int stateCode, int statusCode);
void ChangeState(Entity entity, int stateCode, int statusCode);
}
public sealed class CrmServiceConfiguration
{
public Uri ServerUrl { get; set; }
public string OrganizationName { get; set; }
public string Domain { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool ImpersonateUsingWif { get; set; }
}
public class CrmService : ICrmService
{
#region Private Attributes and Properties
private readonly OrganizationServiceProxy _orgService;
public Guid CallerId
{
get { return _orgService.CallerId; }
set { _orgService.CallerId = value; }
}
public Guid? CurrentUserId { get; set; }
#endregion
#region Constructor
public CrmService(CrmServiceConfiguration config)
{
var organizationUri = new Uri(config.ServerUrl, string.Format("{0}/XRMServices/2011/Organization.svc", config.OrganizationName));
var credentials = CreateCredentials(config);
_orgService = new ManagedTokenOrganizationServiceProxy(organizationUri, credentials);
_orgService.EnableProxyTypes();
// Check if we need to impersonate
if (config.ImpersonateUsingWif)
{
CallerId = GetCallerId();
_orgService.CallerId = CallerId;
}
CurrentUserId = GetCurrentUserId();
}
private Guid? GetCurrentUserId()
{
var response = _orgService.Execute(new WhoAmIRequest());
if (response == null || response.Results.Count == 0)
return null;
return (Guid) response.Results["UserId"];
}
#region Credentials
private ClientCredentials CreateCredentials(CrmServiceConfiguration config)
{
var credentials = new ClientCredentials();
if (string.IsNullOrWhiteSpace(config.Username)) {
credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
return credentials;
}
if (!string.IsNullOrWhiteSpace(config.Domain)) {
credentials.Windows.ClientCredential = new NetworkCredential(config.Username, config.Password, config.Domain);
}
else {
credentials.UserName.UserName = config.Username;
credentials.UserName.Password = config.Password;
}
return credentials;
}
#endregion
#endregion
#region WIF Impersonation
private Guid GetCallerId()
{
var columnSet = new ColumnSet("domainname", "fullname");
var filter = new FilterExpression();
// WIF passes through our domain name
filter.AddCondition("domainname", ConditionOperator.Equal, Thread.CurrentPrincipal.Identity.Name);
var response = Retrieve("systemuser", filter, columnSet);
// Take the first user that fits - usualy there will be only one
if (response.Count > 0) {
return response[0].Id;
}
HttpContext.Current.Response.StatusCode = 403;
HttpContext.Current.Response.End();
return Guid.Empty;
}
#endregion
#region Helpers
private ColumnSet GenerateColumnSet<T>() where T : Entity
{
var columns = new ColumnSet(false);
// Iterate through all properties and check for attributes
var entityProperties = typeof(T).GetProperties();
foreach (var property in entityProperties)
{
var attribute = property.GetFirstOrDefaultCustomAttribute<AttributeLogicalNameAttribute>();
if (attribute != null) {
columns.AddColumn(attribute.LogicalName);
}
}
return columns;
}
private FilterExpression CreateSimpleFilter(string attribute, object value)
{
var filter = new FilterExpression(LogicalOperator.And);
filter.AddCondition(attribute, ConditionOperator.Equal, value);
return filter;
}
#endregion
#region Gets
public Entity Get(string entityLogicalName, Guid entityId, ColumnSet columns)
{
return _orgService.Retrieve(entityLogicalName, entityId, columns);
}
public T Get<T>(Guid entityId) where T : Entity
{
//var entityInstance = Activator.CreateInstance<T>();
var entityName = typeof(T).GetLogicalName();
var columnSet = GenerateColumnSet<T>();
var baseEntity = _orgService.Retrieve(entityName, entityId, columnSet);
Mapper.CreateMap<Entity, T>();
return Mapper.Map<T>(baseEntity);
}
#endregion
#region Retrieves
#region Singles
public Entity Single(string entityLogicalName, string attribute, object value, ColumnSet columns)
{
var filter = CreateSimpleFilter(attribute, value);
var results = Retrieve(entityLogicalName, filter, columns);
return SingleInternal(results);
}
public T Single<T>(string attribute, object value) where T : Entity
{
var filter = CreateSimpleFilter(attribute, value);
var results = Retrieve<T>(filter);
return SingleInternal(results);
}
private T SingleInternal<T>(IList<T> results) where T : Entity
{
var resultCount = results.Count;
// No result
if (resultCount == 0) {
return null;
}
// More than one
if (resultCount > 1) {
throw new InvalidOperationException("Current filter returned more than one record, consider using Retrieve instead.");
}
return results[0];
}
#endregion
public IList<Entity> Retrieve(string entityLogicalName, string attribute, object value, ColumnSet columns)
{
var filter = CreateSimpleFilter(attribute, value);
return Retrieve(entityLogicalName, filter, columns);
}
public IList<T> Retrieve<T>(string attribute, object value) where T : Entity
{
var filter = CreateSimpleFilter(attribute, value);
return Retrieve<T>(filter);
}
public IList<Entity> Retrieve(string entityLogicalName, FilterExpression filter, ColumnSet columns)
{
var query = new QueryExpression(entityLogicalName) {
Criteria = filter,
ColumnSet = columns
};
return Retrieve(query);
}
public IList<T> Retrieve<T>(FilterExpression filter) where T : Entity
{
var query = new QueryExpression(typeof(T).GetLogicalName())
{
ColumnSet = GenerateColumnSet<T>(),
Criteria = filter
};
return Retrieve<T>(query);
}
public IList<Entity> Retrieve(QueryBase query)
{
var results = _orgService.RetrieveMultiple(query);
return results.Entities.ToList();
}
public IList<T> Retrieve<T>(QueryBase query) where T : Entity
{
var results = _orgService.RetrieveMultiple(query);
Mapper.CreateMap<Entity, T>();
return Mapper.Map<IList<T>>(results.Entities);
}
public IList<Entity> Retrieve(string entityLogicalName, ColumnSet columns)
{
return Retrieve(entityLogicalName, null, columns);
}
public IList<T> Retrieve<T>() where T : Entity
{
return Retrieve<T>((FilterExpression) null);
}
#endregion
#region Fetch
public IList<Entity> Fetch(string fetchXml)
{
int totalCount;
return Fetch(fetchXml, out totalCount);
}
public IList<T> Fetch<T>(string fetchXml) where T : Entity
{
int totalCount;
return Fetch<T>(fetchXml, out totalCount);
}
public IList<Entity> Fetch(string fetchXml, out int totalRecordCount)
{
var query = new FetchExpression(fetchXml);
var results = _orgService.RetrieveMultiple(query);
totalRecordCount = results.TotalRecordCount;
return results.Entities.ToList();
}
public IList<T> Fetch<T>(string fetchXml, out int totalRecordCount)
{
var query = new FetchExpression(fetchXml);
var results = _orgService.RetrieveMultiple(query);
totalRecordCount = results.TotalRecordCount;
Mapper.CreateMap<Entity, T>();
return Mapper.Map<IList<T>>(results.Entities);
}
#endregion
#region Creates
public Guid Create(Entity entity)
{
return Create<Entity>(entity);
}
public Guid Create<T>(T entity) where T : Entity
{
if (string.IsNullOrEmpty(entity.LogicalName))
entity.LogicalName = typeof(T).GetLogicalName();
return _orgService.Create(entity);
}
#endregion
#region Updates
public void Update(Entity entity)
{
Update<Entity>(entity);
}
public void Update<T>(T entity) where T : Entity
{
if (string.IsNullOrEmpty(entity.LogicalName))
entity.LogicalName = typeof(T).GetLogicalName();
_orgService.Update(entity);
}
#endregion
#region Deletes
public void Delete(string entityLogicalName, Guid entityId)
{
_orgService.Delete(entityLogicalName, entityId);
}
public void Delete<T>(T entity) where T : Entity
{
Delete(entity.LogicalName, entity.Id);
}
#endregion
#region Misc
public OrganizationResponse Execute(OrganizationRequest request)
{
return _orgService.Execute(request);
}
public string RetrieveOptionSetLabel(string entityName, string attribute, int value)
{
var attributeRequest = new RetrieveAttributeRequest {
EntityLogicalName = entityName,
LogicalName = attribute,
RetrieveAsIfPublished = true
};
try
{
var response = _orgService.Execute(attributeRequest) as RetrieveAttributeResponse;
if (response == null) {
return null;
}
// PicklistAttributeMetadata in StateAttributeMetadata
var metadata = response.AttributeMetadata as EnumAttributeMetadata;
if (metadata == null) {
return null;
}
var option = metadata.OptionSet.Options.SingleOrDefault(o => o.Value == value);
return option != null ? option.Label.UserLocalizedLabel.Label : null;
}
catch (Exception) {
return null;
}
}
public void ChangeState(string entityName, Guid entityId, int stateCode, int statusCode)
{
var changeRequest = new SetStateRequest {
EntityMoniker = new EntityReference(entityName, entityId),
State = new OptionSetValue(stateCode),
Status = new OptionSetValue(statusCode)
};
_orgService.Execute(changeRequest);
}
public void ChangeState(Entity entity, int stateCode, int statusCode)
{
ChangeState(entity.LogicalName, entity.Id, stateCode, statusCode);
}
#endregion
#region IDisposable
public void Dispose()
{
_orgService.Dispose();
}
#endregion
}
}