/// <summary> /// Pass Extended OrganizationService to context /// </summary> /// <param name="cxInfo">IConnectionInfo</param> /// <returns>Constructor argument(s)</returns> public override object[] GetContextConstructorArguments(IConnectionInfo cxInfo) { // Instantiate CrmProperties. CrmProperties props = new CrmProperties(cxInfo); return(new object[] { new Uri(props.OrgUri + "/api/data/v" + props.Version + "/") }); }
/// <summary> /// Pass Extended OrganizationService to context /// </summary> /// <param name="cxInfo">IConnectionInfo</param> /// <returns>Constructor argument(s)</returns> public override object[] GetContextConstructorArguments(IConnectionInfo cxInfo) { // Instantiate CrmProperties. CrmProperties props = new CrmProperties(cxInfo); // Create CrmConnection depending on connection type. CrmServiceClient crmConn = null; switch (props.AuthenticationProviderType) { case AuthenticationProviderType.OnlineFederation: crmConn = new CrmServiceClient( $"AuthType=Office365; Username={props.UserName}; Password={props.Password}; Url={props.OrgUri}"); break; case AuthenticationProviderType.ActiveDirectory: if (String.IsNullOrEmpty(props.DomainName)) { crmConn = new CrmServiceClient($"Url={props.OrgUri};"); } else { crmConn = new CrmServiceClient( $"Url={props.OrgUri}; Domain={props.DomainName}; Username={props.UserName}; Password={props.Password};"); } break; case AuthenticationProviderType.Federation: crmConn = new CrmServiceClient( $"AuthType=IFD; Url={props.OrgUri}{props.ConnectedOrgUniqueName}; Domain={props.DomainName}; Username={props.UserName}; Password={props.Password};"); break; } if (crmConn != null && crmConn.IsReady) { orgService = new OrganizationServiceEx(crmConn); } return(new object[] { orgService }); }
/// <summary> /// Additional work for Initialization. Hook PreExecute event to display QueryExpression and FetchXML to SQL tab. /// </summary> /// <param name="cxInfo">IConnectionInfo</param> /// <param name="context">Context generated via CSDL</param> /// <param name="executionManager">QueryExecutionManager</param> public override void InitializeContext(IConnectionInfo cxInfo, object context, QueryExecutionManager executionManager) { CrmProperties props = new CrmProperties(cxInfo); // Set AccessToken when calling REST Endpoint. (context as Microsoft.OData.Client.DataServiceContext).SendingRequest2 += (s, e) => { switch (props.AuthenticationProviderType) { // If this is for CRM Online, then use OAuth 2.0 case "OnlineFederation": case "Federation": AuthenticationContext authContext = new AuthenticationContext(props.Authority, false); string accessToken; try { // Try to get token without prompt fist. accessToken = authContext.AcquireTokenSilent(props.OrgUri, props.ClientId).AccessToken; } catch { // If AcquireTokenSilent fails, then use another way if (props.AuthenticationProviderType == "OnlineFederation") { try { // Try to use embed credential accessToken = authContext.AcquireToken(props.OrgUri, props.ClientId, new UserCredential(props.UserName, props.Password)).AccessToken; } catch (Exception ex) { // If failed, need to try using consent. accessToken = authContext.AcquireToken(props.OrgUri, props.ClientId, new Uri(props.RedirectUri), PromptBehavior.Always, new UserIdentifier(props.UserName, UserIdentifierType.RequiredDisplayableId)).AccessToken; } } else { accessToken = authContext.AcquireToken(props.OrgUri, props.ClientId, new Uri(props.RedirectUri), PromptBehavior.Always).AccessToken; } } e.RequestMessage.SetHeader("Authorization", "Bearer " + accessToken); break; // If this is ActiveDirectory, then use Windows Integrated Authentication. // Web API is only supported Online at the moment, so comment out the following for future use. case "ActiveDirectory": if (String.IsNullOrEmpty(props.DomainName)) { (e.RequestMessage as HttpWebRequestMessage).Credentials = CredentialCache.DefaultCredentials; } else { (e.RequestMessage as HttpWebRequestMessage).Credentials = new NetworkCredential(props.UserName, props.Password, props.DomainName); } break; } LINQPad.Util.ClearResults(); executionManager.SqlTranslationWriter.WriteLine(e.RequestMessage.Url); }; base.InitializeContext(cxInfo, context, executionManager); }
// Display Name for connection. public override string GetConnectionDescription(IConnectionInfo cxInfo) { CrmProperties props = new CrmProperties(cxInfo); return(props.FriendlyName + "(Web API) " + props.OrgUri); }
/// <summary> /// Generate Schema information. /// </summary> /// <param name="cxInfo">IConnectionInfo</param> /// <param name="customType">Context Type</param> /// <returns>Schema Information.</returns> public override List <ExplorerItem> GetSchema(IConnectionInfo cxInfo, Type customType) { // Instantiate CrmProperties. CrmProperties props = new CrmProperties(cxInfo); // Instantiate ExplorerItem list. List <ExplorerItem> schema = new List <ExplorerItem>(); // Create Tables for Schema. foreach (PropertyInfo prop in customType.GetRuntimeProperties()) { // If property is not Generic Type or IQueryable, then ignore. if (!prop.PropertyType.IsGenericType || prop.PropertyType.Name != "DataServiceQuery`1") { continue; } // Create ExploreItem with Table icon as this is top level item. ExplorerItem item = new ExplorerItem(prop.Name, ExplorerItemKind.QueryableObject, ExplorerIcon.Table) { // Store Entity Type to Tag. Tag = prop.PropertyType.GenericTypeArguments[0].Name, IsEnumerable = true, Children = new List <ExplorerItem>() }; schema.Add(item); } schema = schema.OrderBy(x => x.Text).ToList <ExplorerItem>(); // Then create columns for each table. Loop through tables again. foreach (PropertyInfo prop in customType.GetRuntimeProperties()) { // Obtain Table item from table lists. var item = schema.Where(x => x.Text == prop.Name).FirstOrDefault(); if (item == null) { continue; } // Get all property from Entity for the table. (i.e. Account for AccountSet) foreach (PropertyInfo childprop in customType.Module.GetTypes().Where(x => x.Name == prop.PropertyType.GenericTypeArguments[0].Name).First().GetRuntimeProperties()) { // If property is IEnumerable type, then it is 1:N or N:N relationship field. // Need to find a way to figure out if this is 1:N or N:N. At the moment, I just make them as OneToMany type. if (childprop.PropertyType.IsGenericType && childprop.PropertyType.Name == "IEnumerable`1") { // Try to get LinkTarget. ExplorerItem linkTarget = schema.Where(x => x.Tag.ToString() == childprop.PropertyType.GetGenericArguments()[0].Name).FirstOrDefault(); if (linkTarget == null) { continue; } // Create ExplorerItem as Colleciton Link. item.Children.Add( new ExplorerItem( childprop.Name, ExplorerItemKind.CollectionLink, ExplorerIcon.OneToMany) { HyperlinkTarget = linkTarget, ToolTipText = DataContextDriver.FormatTypeName(childprop.PropertyType, false) }); } else { // Try to get LinkTarget to check if this field is N:1. ExplorerItem linkTarget = schema.Where(x => x.Tag.ToString() == childprop.PropertyType.Name).FirstOrDefault(); // If no linkTarget exists, then this is normal field. if (linkTarget == null) { // Create ExplorerItem as Column. item.Children.Add( new ExplorerItem( childprop.Name + " (" + DataContextDriver.FormatTypeName(childprop.PropertyType, false) + ")", ExplorerItemKind.Property, ExplorerIcon.Column) { ToolTipText = DataContextDriver.FormatTypeName(childprop.PropertyType, false) }); } else { // Otherwise, create ExploreItem as N:1 item.Children.Add( new ExplorerItem( childprop.Name + " (" + DataContextDriver.FormatTypeName(childprop.PropertyType, false) + ")", ExplorerItemKind.ReferenceLink, ExplorerIcon.ManyToOne) { HyperlinkTarget = linkTarget, ToolTipText = DataContextDriver.FormatTypeName(childprop.PropertyType, false) }); } } // Order Fields item.Children = item.Children.OrderBy(x => x.Text).ToList <ExplorerItem>(); } } // Order Entities. schema = schema.OrderBy(x => x.Text).ToList <ExplorerItem>(); return(schema); }