As of this moment, we still don’t have SDK for V9; however, I did want to see how far can we go with Multi Select Option Sets, and, in particular, if we can work with those option sets on the .NET side since that was the only remaining question in the post I wrote the other day:
Dynamics 365 (V9): Multi Select Option Set
It turned out we can do it with the V8 SDK, even though that’s a little more involved than usual.
To start with, Dynamics web service turned out to be smarter than I thought
To some extent (I don’t know exactly to what extent), it’s backward compatible, and that kind of compatibility is built around the SdkClientVersion parameter that’s included into the requests:
The way I understand it, if there is a feature that is not supported on the client side, that feature will not be added to the response. That might be a bit of a generalization, but, in the end, when a request is made to the service from V8 sdk and if, as part of the response, the web service is supposed to return a Multi Select Option Set attribute, it will simply return null, no matter if there is a value in that field or not.
We can overcome that problem if we override SdkClientVersion property of the
CrmServiceClient.OrganizationServiceProxy
In other words, we can do this:
Microsoft.Xrm.Tooling.Connector.CrmServiceClient conn = …
conn.OrganizationServiceProxy.SdkClientVersion = “9.0.0.2072”;
Unfortunately, that’s not, really, enough to make it work, yet.
V8 version of the SDK does not know how to work with the OptionSetValueCollection, and that’s the expected type name of the Multi Select Option Set. That’s understandable since that type does not exist in the V8 version.
So, when I tried it with the modified SdkClientVersion, I got an error saying that I need to modify my DataContractResolver etc etc.
Which, eventually, I did.. Here goes the code that you can add to your project if you wanted to try the same – just put it in a new “cs” file and add that file to your project:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Xml; using System.ServiceModel.Description; using Microsoft.Xrm.Sdk; namespace DynamicsHelpersV9 { [CollectionDataContract(Name = "OptionSetValueCollection", Namespace = "http://schemas.microsoft.com/xrm/9.0/Contracts")] public class OptionSetValueCollection : List { } public class DynamicsDataContractResolver : DataContractResolver { DataContractResolver origResolver = null; public DynamicsDataContractResolver(DataContractResolver origResolver) { this.origResolver = origResolver; } public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) { bool result = origResolver.TryResolveType(type, declaredType, knownTypeResolver, out typeName, out typeNamespace); return result; } public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver) { Type result = origResolver.ResolveName(typeName, typeNamespace, declaredType, knownTypeResolver); if (result == null && typeName == "OptionSetValueCollection") { result = Type.GetType("DynamicsHelpersV9.OptionSetValueCollection"); } return result; } public static void SetupCRMServiceClient(Microsoft.Xrm.Tooling.Connector.CrmServiceClient conn) { conn.OrganizationServiceProxy.SdkClientVersion = "9.0.0.2072"; foreach (var serviceEndpoint in conn.OrganizationServiceProxy.ServiceConfiguration.ServiceEndpoints.Values) { foreach (var operation in serviceEndpoint.Contract.Operations) { var serializerBehavior = operation.OperationBehaviors .OfType().FirstOrDefault(); if (serializerBehavior == null) { serializerBehavior = new DataContractSerializerOperationBehavior(operation); operation.OperationBehaviors.Add(serializerBehavior); } serializerBehavior.DataContractResolver = new DynamicsDataContractResolver(serializerBehavior.DataContractResolver); } } } } }
Once you have that, the rest is simple:
You will need to create a CrmServiceClient:
var conn = new Microsoft.Xrm.Tooling.Connector.CrmServiceClient(…)
Then, you’ll need to use that helper class above to set up your CrmServiceClient:
DynamicsHelpersV9.DynamicsDataContractResolver.SetupCRMServiceClient(conn);
Get the OrganizationService:
IOrganizationService service = (IOrganizationService)conn.OrganizationWebProxyClient != null ? (IOrganizationService)conn.OrganizationWebProxyClient : (IOrganizationService)conn.OrganizationServiceProxy;
And, finally, do what you need with the OptionSetValueCollection attribute:
var results = service.RetrieveMultiple(new FetchExpression(fetchXml)).Entities;
var r = (DynamicsHelpersV9.OptionSetValueCollection)results[0][“new_testmultiselect”];
r.RemoveAt(0);
service.Update(results[0]);
I’m pretty sure this will all be available “out of the box” once we have V9 version of the SDK, but, even now, it seems we can already start using Multi Select Option Sets in the Dynamics-integrated applications.
operation.OperationBehaviors.OfType().FirstOrDefault()
The type arguments for method ‘Queryable.OfType(IQueryable)’ cannot be inferred from usage. Try specifying the type arguments explicitly.