| | 1 | | using Microsoft.Crm.Sdk.Messages; |
| | 2 | | using Microsoft.Xrm.Sdk; |
| | 3 | | using Microsoft.Xrm.Sdk.Messages; |
| | 4 | | using Microsoft.Xrm.Sdk.Query; |
| | 5 | | using System; |
| | 6 | | using System.Collections.Generic; |
| | 7 | | using System.Linq; |
| | 8 | | using System.ServiceModel; |
| | 9 | | using System.Xml.Linq; |
| | 10 | |
|
| | 11 | | namespace FakeXrmEasy.FakeMessageExecutors |
| | 12 | | { |
| | 13 | | public class ExecuteFetchRequestExecutor : IFakeMessageExecutor |
| | 14 | | { |
| 4295 | 15 | | private Dictionary<string, int?> _typeCodes = new Dictionary<string, int?>(); |
| | 16 | |
|
| | 17 | | public bool CanExecute(OrganizationRequest request) |
| 42 | 18 | | { |
| 42 | 19 | | return request is ExecuteFetchRequest; |
| 42 | 20 | | } |
| | 21 | |
|
| | 22 | | public OrganizationResponse Execute(OrganizationRequest request, XrmFakedContext ctx) |
| 42 | 23 | | { |
| 42 | 24 | | var executeFetchRequest = (ExecuteFetchRequest)request; |
| | 25 | |
|
| 42 | 26 | | if (executeFetchRequest.FetchXml == null) |
| 0 | 27 | | { |
| 0 | 28 | | throw new FaultException<OrganizationServiceFault>(new OrganizationServiceFault(), "You need to provide |
| | 29 | | } |
| | 30 | |
|
| 42 | 31 | | var service = ctx.GetFakedOrganizationService(); |
| | 32 | |
|
| 42 | 33 | | var retrieveMultiple = new RetrieveMultipleRequest() |
| 42 | 34 | | { |
| 42 | 35 | | Query = new FetchExpression(executeFetchRequest.FetchXml) |
| 42 | 36 | | }; |
| 42 | 37 | | var queryResult = (service.Execute(retrieveMultiple) as RetrieveMultipleResponse).EntityCollection; |
| | 38 | |
|
| 42 | 39 | | XDocument doc = new XDocument(new XElement("resultset", |
| 42 | 40 | | new XAttribute("morerecords", Convert.ToInt16(queryResult.MoreRecords)))); |
| 42 | 41 | | if (queryResult.PagingCookie != null) |
| 18 | 42 | | { |
| 18 | 43 | | doc.Root.Add(new XAttribute("paging-cookie", queryResult.PagingCookie)); |
| 18 | 44 | | } |
| | 45 | |
|
| 42 | 46 | | var allowedAliases = new string[0]; |
| | 47 | |
|
| 42 | 48 | | var fetchXmlDocument = XDocument.Parse(executeFetchRequest.FetchXml).Root; |
| 42 | 49 | | if (fetchXmlDocument != null) |
| 42 | 50 | | { |
| 66 | 51 | | var linkedEntityName = fetchXmlDocument.Descendants("link-entity").Attributes("name").Select(a => a.Valu |
| 48 | 52 | | allowedAliases = linkedEntityName.Concat(fetchXmlDocument.Descendants("link-entity").Attributes("alias") |
| 42 | 53 | | } |
| | 54 | |
|
| 510 | 55 | | foreach (var row in queryResult.Entities) |
| 192 | 56 | | { |
| 192 | 57 | | doc.Root.Add(CreateXmlResult(row, ctx, allowedAliases)); |
| 192 | 58 | | } |
| | 59 | |
|
| 42 | 60 | | var response = new ExecuteFetchResponse |
| 42 | 61 | | { |
| 42 | 62 | | Results = new ParameterCollection |
| 42 | 63 | | { |
| 42 | 64 | | { "FetchXmlResult", doc.ToString() } |
| 42 | 65 | | } |
| 42 | 66 | | }; |
| | 67 | |
|
| 42 | 68 | | return response; |
| 42 | 69 | | } |
| | 70 | |
|
| | 71 | | private XElement CreateXmlResult(Entity entity, XrmFakedContext ctx, string[] allowedAliases) |
| 192 | 72 | | { |
| 192 | 73 | | var row = new XElement("result"); |
| 192 | 74 | | var formattedValues = entity.FormattedValues; |
| | 75 | |
|
| 1152 | 76 | | foreach (var entAtt in entity.Attributes) |
| 288 | 77 | | { |
| 288 | 78 | | var attribute = entAtt; |
| | 79 | |
|
| | 80 | | // Depricated ExecuteFetch doesn't use implicitly numbered enitity aliases |
| 288 | 81 | | if (attribute.Key.Contains(".")) |
| 24 | 82 | | { |
| 24 | 83 | | var alias = attribute.Key.Substring(0, attribute.Key.IndexOf(".", StringComparison.Ordinal)); |
| 24 | 84 | | if (!allowedAliases.Contains(alias)) |
| 18 | 85 | | { |
| | 86 | | // The maximum amount of linked entities is 10, |
| 18 | 87 | | var newAlias = alias.Substring(0, alias.Length - (!alias.EndsWith("10") ? 1 : 2)); |
| 18 | 88 | | if (allowedAliases.Contains(newAlias)) |
| 18 | 89 | | { |
| 18 | 90 | | var newKey = attribute.Key.Split(new[] {'.'}, StringSplitOptions.RemoveEmptyEntries); |
| 18 | 91 | | newKey[0] = newAlias; |
| 18 | 92 | | attribute = new KeyValuePair<string, object>(string.Join(".", newKey), attribute.Value); |
| 18 | 93 | | } |
| | 94 | | else |
| 0 | 95 | | { |
| | 96 | | // unknow alias, just leave it |
| 0 | 97 | | } |
| 18 | 98 | | } |
| 24 | 99 | | } |
| | 100 | |
|
| 288 | 101 | | var attributeValueElement = AttributeValueToFetchResult(attribute, formattedValues, ctx); |
| 288 | 102 | | if (attributeValueElement == null) |
| 0 | 103 | | { |
| 0 | 104 | | continue; |
| | 105 | | } |
| | 106 | |
|
| 288 | 107 | | row.Add(attributeValueElement); |
| 288 | 108 | | } |
| | 109 | |
|
| 192 | 110 | | return row; |
| 192 | 111 | | } |
| | 112 | |
|
| | 113 | | public XElement AttributeValueToFetchResult(KeyValuePair<string, object> entAtt, FormattedValueCollection format |
| 343 | 114 | | { |
| | 115 | | XElement attributeValueElement; |
| 343 | 116 | | if (entAtt.Value == null) |
| 0 | 117 | | return null; |
| 343 | 118 | | if (entAtt.Value is DateTime?) |
| 18 | 119 | | { |
| 18 | 120 | | attributeValueElement = XElement.Parse(String.Format("<{0} date=\"{1:yyyy-MM-dd}\" time=\"{1:hh:mm tt}\" |
| 18 | 121 | | } |
| 325 | 122 | | else if (entAtt.Value is EntityReference) |
| 24 | 123 | | { |
| 24 | 124 | | var entRef = (EntityReference)entAtt.Value; |
| 24 | 125 | | if (!_typeCodes.ContainsKey(entRef.LogicalName)) |
| 24 | 126 | | { |
| 24 | 127 | | var entType = RetrieveEntityRequestExecutor.GetEntityProxyType(entRef.LogicalName, ctx); |
| 24 | 128 | | var typeCode = entType.GetField("EntityTypeCode").GetValue(null); |
| | 129 | |
|
| 24 | 130 | | _typeCodes.Add(entRef.LogicalName, (int?)typeCode); |
| 24 | 131 | | } |
| | 132 | |
|
| 24 | 133 | | attributeValueElement = XElement.Parse(String.Format("<{0} dsc=\"0\" yomi=\"{1}\" name=\"{1}\" type=\"{3 |
| 24 | 134 | | } |
| 301 | 135 | | else if (entAtt.Value is bool?) |
| 6 | 136 | | { |
| 6 | 137 | | var boolValue = (bool?)entAtt.Value; |
| | 138 | |
|
| 6 | 139 | | var formattedValue = boolValue.ToString(); |
| 6 | 140 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| 0 | 141 | | formattedValue = formattedValues[entAtt.Key]; |
| 6 | 142 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\">{2}</{0}>", entAtt.Key, formatte |
| 6 | 143 | | } |
| 295 | 144 | | else if (entAtt.Value is OptionSetValue) |
| 12 | 145 | | { |
| 12 | 146 | | var osValue = (OptionSetValue)entAtt.Value; |
| | 147 | |
|
| 12 | 148 | | var formattedValue = osValue.Value.ToString(); |
| 12 | 149 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| 6 | 150 | | formattedValue = formattedValues[entAtt.Key]; |
| 12 | 151 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\" formattedvalue=\"{2}\">{2}</{0}> |
| 12 | 152 | | } |
| 283 | 153 | | else if (entAtt.Value is Enum) |
| 0 | 154 | | { |
| 0 | 155 | | var osValue = (Enum)entAtt.Value; |
| | 156 | |
|
| 0 | 157 | | var formattedValue = osValue.ToString(); |
| 0 | 158 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| 0 | 159 | | formattedValue = formattedValues[entAtt.Key]; |
| 0 | 160 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\" formattedvalue=\"{2}\">{2}</{0}> |
| 0 | 161 | | } |
| 283 | 162 | | else if (entAtt.Value is Money) |
| 6 | 163 | | { |
| 6 | 164 | | var moneyValue = (Money)entAtt.Value; |
| | 165 | |
|
| 6 | 166 | | var formattedValue = moneyValue.Value.ToString(); |
| 6 | 167 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| 0 | 168 | | formattedValue = formattedValues[entAtt.Key]; |
| 6 | 169 | | attributeValueElement = XElement.Parse(String.Format("<{0} formattedvalue=\"{1}\">{2:0.##}</{0}>", entAt |
| 6 | 170 | | } |
| 277 | 171 | | else if (entAtt.Value is decimal?) |
| 0 | 172 | | { |
| 0 | 173 | | var decimalVal = (decimal?)entAtt.Value; |
| | 174 | |
|
| 0 | 175 | | attributeValueElement = XElement.Parse(String.Format("<{0}>{1:0.####}</{0}>", entAtt.Key, decimalVal.Val |
| 0 | 176 | | } |
| 277 | 177 | | else if (entAtt.Value is AliasedValue) |
| 30 | 178 | | { |
| 30 | 179 | | var alliasedVal = entAtt.Value as AliasedValue; |
| 30 | 180 | | attributeValueElement = AttributeValueToFetchResult(new KeyValuePair<string, object>(entAtt.Key, alliase |
| 30 | 181 | | } |
| 247 | 182 | | else if (entAtt.Value is Guid) |
| 192 | 183 | | { |
| 384 | 184 | | attributeValueElement = XElement.Parse(String.Format("<{0}>{1}</{0}>", entAtt.Key, entAtt.Value.ToString |
| 192 | 185 | | } |
| | 186 | | #if FAKE_XRM_EASY_9 |
| 10 | 187 | | else if (entAtt.Value is OptionSetValueCollection) |
| 1 | 188 | | { |
| 1 | 189 | | var optionSetValueCollectionVal = entAtt.Value as OptionSetValueCollection; |
| 5 | 190 | | var values = String.Join(",", optionSetValueCollectionVal.Select(o => o.Value).OrderBy(v => v)); |
| 1 | 191 | | var serializedCollection = String.Join(",", "[-1", values, "-1]"); |
| 1 | 192 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\">{1}</{0}>", entAtt.Key, serializ |
| 1 | 193 | | } |
| | 194 | | #endif |
| | 195 | | else |
| 54 | 196 | | { |
| 54 | 197 | | attributeValueElement = XElement.Parse(String.Format("<{0}>{1}</{0}>", entAtt.Key, entAtt.Value)); |
| 54 | 198 | | } |
| 343 | 199 | | return attributeValueElement; |
| 343 | 200 | | } |
| | 201 | |
|
| | 202 | | public Type GetResponsibleRequestType() |
| 4270 | 203 | | { |
| 4270 | 204 | | return typeof(ExecuteFetchRequest); |
| 4270 | 205 | | } |
| | 206 | | } |
| | 207 | | } |