Add note [annotation] in Dynamics CRM using Csharp

Notes in Dynamics CRM can be associated to any entity like Account, Sales Order, Order, Contact, Opportunity e.t.c; To programatically attach a note to an entity please follow the code below:

Annotation object in CRM has the following structure

Note:
has title, description and an attachment.

Following class holds an object that represents a note object in CRM.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
    public class NoteGeneric
    {
        public string ReferenceId { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public System.Web.HttpPostedFileBase file { get; set; }
        public string Description { get; set; }
        public string NoteText { get; set; }
        public string DocumentBody { get; set; }
        public string Subject { get; set; }
        public string FileName { get; set; }
        public string FileType { get; set; }
        public bool HasDocument { get; set; }
 
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
        public Response AddNotes(NoteGeneric note, string EntityName)
        {
            try
            {
                var crmService = GetCRMService(note.Email, note.Password);
 
                var annotation = new Entity("annotation");
 
                annotation.Attributes["objectid"] = new EntityReference(EntityName,
                    new Guid(note.ReferenceOpportunityId));
                annotation.Attributes["objecttypecode"] = EntityName;
                annotation.Attributes["subject"] = note.Subject;
                annotation.Attributes["notetext"] = note.NoteText;
                annotation.Attributes["createdon"] = DateTime.Now.ToLocalTime();
                if (note.HasDocument)
                {
                    annotation.Attributes["mimetype"] = note.FileType;
                    annotation.Attributes["documentbody"] = note.DocumentBody;
                    annotation.Attributes["filename"] = note.FileName;
                }
 
                crmService.Create(annotation);
                return new Response() {Message = "success"};
            }
            catch (Exception err)
            {
                return new Response() {Message = "failure"};
            }
        }

For GetCRMService method, see this post. LINK TO PART 1

Above method will attach the document only if HasDocument property is set to true, in other case, it will at a note without the attachment.

crmService.Create method saves/associated the annotation to the entity.

Part 3-b – Dynamic CRM Series – Fetch some data using CRM SDK in C#

LINK TO PART 1 – Connection

LINK TO PART 2 – Authentication

LINK TO PART 3 – Fetch Data through Fetch XML

LINK TO PART 4 – Fetch Data through CRM SDK

In the last post we fetched some account list using FETCH XML technique, in this blog post, we will do the same but using CRM SDK, utilising this method is more familiar to C# developers.

Below is the method to fetch accounts list from dynamics CRM using CRM SDK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 
    public class BasicAccountInfo
    {
        public string code { get; set; }
        public string name { get; set; }
    }
 
        /// <summary>
        /// Get all user accounts in CRM
        /// </summary>
        /// <param name="email"></param>
        /// <param name="password"></param>
        /// <param name="searchphrase"></param>
        /// <returns></returns>
        public List<BasicAccountInfo> GetUserAccountsWeb(string email, string password)
        {
            var finalResult = new List<BasicAccountInfo>();
            var crmService = GetCRMService(email, password);
 
            var query = new QueryExpression("account") {ColumnSet = new ColumnSet("name", "accountid")};
 
            ConditionExpression condition = new ConditionExpression
            {
                AttributeName = "name",
                Operator = ConditionOperator.NotNull
            };
 
            FilterExpression filter = new FilterExpression();
            filter.FilterOperator = LogicalOperator.And;
            filter.Conditions.Add(condition);
 
            query.Criteria.AddFilter(filter);
            query.Distinct = true;
 
            EntityCollection result = crmService.RetrieveMultiple(query);
            var finalResult = (from data in result.Entities
                                       select new
                                       {
                                           code = ((Microsoft.Xrm.Sdk.Entity)(data)).Attributes["accountid"].ToString(),
                                           name = ((Microsoft.Xrm.Sdk.Entity)(data)).Attributes["name"].ToString()
                                       }).ToList();
 
 
            return finalResult;
        }

Part 3-a – Dynamic CRM Series – Fetch some data using FetchXML in C#

LINK TO PART 1 – Connection

LINK TO PART 2 – Authentication

LINK TO PART 3 – Fetch Data through Fetch XML

LINK TO PART 4 – Fetch Data through CRM SDK

FetchXML is a proprietary query language that is used in Microsoft Dynamics 365 (online & on-premises). It’s based on a schema that describes the capabilities of the language.

Based on our previous two posts, let us say now we have our organization service proxy, and we need to fetch the list of accounts in our CRM SDK, here is what we can do.

Below is a simple method to fetch the names of accounts from accounts entity in dynamics crm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
public class BasicAccountInfo
    {
        public string code { get; set; }
        public string name { get; set; }
    }
 
        /// <summary>
        /// Get all user accounts in CRM
        /// </summary>
        /// <param name="email"></param>
        /// <param name="password"></param>
        /// <param name="searchphrase"></param>
        /// <returns></returns>
        public List<BasicAccountInfo> GetUserAccountsWeb(string email, string password)
        {
            var finalResult = new List<BasicAccountInfo>();
            var crmService = GetCRMService(email, password);
            string fetchXml = "";
 
 
                fetchXml = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
 			<entity name='account'>
    			<attribute name='name' />
    			<attribute name='accountid' />
    			<order attribute='name' descending='false' />
  			</entity>
			</fetch>";
            }
 
            EntityCollection result = crmService.RetrieveMultiple(new FetchExpression(fetchXml));
            var finalResult = (from data in result.Entities
                                       select new
                                       {
                                           code = ((Microsoft.Xrm.Sdk.Entity)(data)).Attributes["accountid"].ToString(),
                                           name = ((Microsoft.Xrm.Sdk.Entity)(data)).Attributes["name"].ToString()
                                       }).ToList();
 
 
            return finalResult;
        }

Part 2 – Dynamic CRM Series : User Authentication using C#

LINK TO PART 1 – Connection

LINK TO PART 2 – Authentication

LINK TO PART 3 – Fetch Data through Fetch XML

LINK TO PART 4 – Fetch Data through CRM SDK

In our last part of series we made a connection to Dynamic CRM through the CRM SDK.

In this part, we will see how we can authenticate a user using Dynamics CRM.

The following method obtains discovery/organization service proxy for Federated, LiveId and OnlineFederated environments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
        private TProxy GetProxy<TService, TProxy>(
            IServiceManagement<TService> serviceManagement,
            AuthenticationCredentials authCredentials)
            where TService : class
            where TProxy : ServiceProxy<TService>
        {
            Type classType = typeof(TProxy);
 
            if (serviceManagement.AuthenticationType !=
                AuthenticationProviderType.ActiveDirectory)
            {
                AuthenticationCredentials tokenCredentials =
                    serviceManagement.Authenticate(authCredentials);
                // Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. 
                // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse.
                return (TProxy) classType
                    .GetConstructor(new Type[] {typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse)})
                    .Invoke(new object[] {serviceManagement, tokenCredentials.SecurityTokenResponse});
            }
 
            // Obtain discovery/organization service proxy for ActiveDirectory environment.
            // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials.
            return (TProxy) classType
                .GetConstructor(new Type[] {typeof(IServiceManagement<TService>), typeof(ClientCredentials)})
                .Invoke(new object[] {serviceManagement, authCredentials.ClientCredentials});
        }

Following method retrieves the Authentication Credentials from CRM SDK based on authentication provider.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
	private AuthenticationCredentials GetCredentials<TService>(IServiceManagement<TService> service,
            AuthenticationProviderType endpointType, string _userName, string _password)
        {
            AuthenticationCredentials authCredentials = new AuthenticationCredentials();
 
            switch (endpointType)
            {
                case AuthenticationProviderType.ActiveDirectory:
                    authCredentials.ClientCredentials.Windows.ClientCredential =
                        new System.Net.NetworkCredential(_userName,
                            _password,
                            _domain);
                    break;
                case AuthenticationProviderType.LiveId:
                    authCredentials.ClientCredentials.UserName.UserName = _userName;
                    authCredentials.ClientCredentials.UserName.Password = _password;
                    break;
                default: // For Federated and OnlineFederated environments.                    
                    authCredentials.ClientCredentials.UserName.UserName = _userName;
                    authCredentials.ClientCredentials.UserName.Password = _password;
                    if (endpointType == AuthenticationProviderType.OnlineFederation)
                    {
                        IdentityProvider provider =
                            service.GetIdentityProvider(authCredentials.ClientCredentials.UserName.UserName);
                        if (provider != null && provider.IdentityProviderType == IdentityProviderType.LiveId)
                        {
                            authCredentials.SupportingCredentials = new AuthenticationCredentials();
                        }
                    }
 
                    break;
            }
 
            return authCredentials;
        }

And finally, our login method, it returns true if user is authenticated, and false if it is not.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 
public bool Login(string Email, string Password)
        {
            OrganizationService orgService;
            bool isValidUser=false;
            IServiceManagement<IDiscoveryService> serviceManagement =
                ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
                    new Uri(_discoveryServiceAddress));
            AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;
 
            // Set the credentials.
 
            String organizationUri = String.Empty;
            // Get the discovery service proxy.
 
            bool result = false;
            try
            {
                AuthenticationCredentials authCredentials = GetCredentials(serviceManagement, endpointType, Email,
                    Password);
                var response = GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials);
                result = response != null;
            }
            catch (Exception er)
            {
                result = false;
            }
 
            if (result)
            {
		//Although, our job is done here and we can return true, but if we need to get more user details regarding this logged in user then we can now execute the following calls. Specially the WhoAmIRequest() method of CRM SDK
                orgService = GetCRMService(Email, Password);
                Guid userid = ((WhoAmIResponse) orgService.Execute(new WhoAmIRequest())).UserId;
                dynamic systemUser = orgService.Retrieve("systemuser", userid, new ColumnSet(new string[] {"firstname", "lastname"}));
 
                string UserId = userid.ToString();
 
                string UserName = ((Microsoft.Xrm.Sdk.Entity) systemUser).Attributes["firstname"] + " " +
                                     ((Microsoft.Xrm.Sdk.Entity) systemUser).Attributes["lastname"];                
                isValidUser=true;
            }
            else
            {
                string UserId = "";
 
                string UserName = "";
            }
 
            return isValidUser;
 
        }

I really hope the code was helpful in kick starting your project in dynamics CRM, as authenticating a user from dynamics crm would be the first step if we want to start an application user dynamics CRM

Connect to Dynamics CRM through CRM SDK using C#

There are many ways to connect to and access the database of Dynamics CRM database.

a- If you are creating plug-ins, custom workflow activities, or custom XAML workflows, use Dynamics 365 SDK assemblies

https://msdn.microsoft.com/en-us/library/jj602917.aspx?f=255&MSPPError=-2147217396#SDKAssemblies

b- If you are creating Windows applications for Dynamics 365, use XRM tooling assemblies. More information: .NET Development: Use XRM Tooling assemblies

https://msdn.microsoft.com/en-us/library/jj602917.aspx?f=255&MSPPError=-2147217396#XrmTooling

c- If you are creating non-Windows applications for Dynamics 365, use Web API. More information: Use the Microsoft Dynamics 365 Web API

https://msdn.microsoft.com/en-us/library/mt593051.aspx

The way we will see in this article is to connect through CRM SDK and get the connection Service Proxy object.

In web.config file, add the following entry that carrys the connection string for CRM.

<add key=”XrmConnection” value=”Url=https://crm.domainname.com; Username={0}; password={1}” />

Add reference to following Dll’s

CRM SDK Reference

/// <summary>
/// Method globally used to return a CRM Service Proxy Object, which will be used to make futher calls to CRM.
/// </summary>
/// <param name=”userName”></param>
/// <param name=”password”></param>
/// <returns></returns>
private OrganizationService GetCRMService(string userName, string password)
{
try
{
CrmConnection connection =
CrmConnection.Parse(string.Format(ConfigurationManager.AppSettings[“XrmConnection”], userName, password));
OrganizationService orgService = new OrganizationService(connection);
return orgService;
}
catch (Exception ex)
{
return null;
}
}

This method will return the OrganizationService Proxy object that we can use later to fetch the data from Dynamics CRM Entities.

But before doing this we need to Authenticate and Authorise the user. There are two cases, one in which our application does not require the user to see his personalised content, instead the application is a reporting app, or a generic application for all the users of the organisation. In that case, we can fix the username and password for the master user account in web.config file. Make sure that user have enough previledges requried for the application to run.

In other case, if each user has to login into the application and perform his own activities, in that case above method of connection string and accessing through the metho

Productivity Tips for Visual Studio 2017

Visual Studio 2017 is a productivity powerhouse, It is loaded with tons of features that are really awesome and to talk about.

NuGet Package Suggestion for Unrecognized Types

automatically import from nuget

In my opinion, one of the most useful additions to Visual Studio 2017 was the Nuget-based Using Suggestion feature. This feature will recommend installing a specific NuGet package to handle resolving an unrecognized type that is encountered within the editor.

It can be enabled via:

  • Tools > Options > Text Editor > C# > Advanced > Suggest Usings for Types in Nuget Packages

Again – a great feature to speed up your productivity and it sure beats wandering around NuGet or running off to manually download the packages.

Query Syntax in Go To All (Ctrl+T)

filtering query syntax

Another incredibly useful tool introduced within Visual Studio 2017 was query searching within the Go To All (Ctrl+T) search area. This allows you to now quickly search for any file / type / member / or symbol by prefacing your search using the following prefixes:

  • f {file}
  • t {type}
  • m {member}
  • # {symbol}

This can allow you to easily narrow your search within your solution and find exactly what you need fast.

Full Solution Analysis

errors, messages, and warnings for the entire solution

The Full Solution Analysis feature is one that could be helpful to see every error, message, and warning throughout your entire solution (and not just the files that are currently open).

This feature can be enabled via:

  • Tools > Options > Text Editor > C# > Advanced > Enable Full Solution Analysis

If you are a stickler that can’t stand seeing a non-empty Error List, then this is for you.

Lightweight Solution Load

loading projects on demand

Another great feature that can add quite a bit of zing to Visual Studio 2017 is Lightweight Solution Load. This feature will initially load the minimal amount necessary for each project to have them functional within Visual Studio. Individual project files and dependencies will not be loaded or expanded until requested, so you only load what you will need.

This feature can be enabled in two ways; locally:

  • Right-click Project > Enable Lightweight Solution Load

Or globally (for all projects):

  • Tools > Options > Projects and Solutions > General > Lightweight Solution Load

It’s great for large solutions with multiple projects that maybe aren’t all going to be touched for most scenarios or just if you just want Visual Studio to open up a project faster than normal.

Live Unit Testing

Live Unit Testing was one of the features that was touted during the release of Visual Studio 2017, but it isn’t actually enabled by default. This feature will figure out which unit tests are affected by any code changes and the tests will be automatically run. Additionally, it will decorate your code using icons to indicate which code is covered and the status of the test covering that code.

This feature can be enabled in two ways; locally:

  • Test > Live Unit Testing > Start

Or globally (for all projects):

  • Options > Live Unit Testing

Live Unit Testing is super handy for not only seeing what tests are passing and failing, but for examining code coverage as well. This feature is also highly configurable and will allow you to include / exclude specific tests, define the number of threads you want to dedicate to it, configure when the tests are run, and much more.

EditorConfig Style Enforcement

update-editor-styles

Visual Studio 2017 adds support for .editorconfig files within projects to help provide coding style recommendations, which can be useful for large development teams looking to maintain a consistent style across their code base.

You may notice that the ellipses can be incredibly difficult to notice, especially if you are on the dark side. This can easily be adjusted within the IDE to make them far more visible from:

  • Tools > Options > Environment > Fonts and Colors > Suggestion Ellipsis

You can then configure the color to make it “pop” out a bit more :

styled suggestions

While this feature is enabled by default (if an .editorconfig file is present), you can make the process of editing it much easier through Mads Kristensen’s EditorConfig extension, which can be downloaded and will provide full autocompletion, syntax highlighting, and much more.

Keyboard Shortcuts

With many of the new additions and features that were added to Visual Studio 2017, you might be inclined to consider dropping support for the heavyweight Resharper extension to see how vanilla Visual Studio works at this point. Or if you are a developer coming from another editor such as IntelliJ, Eclipse, you are probably pretty accustomed to the keyboard shortcuts from those tools. Well, there’s an extension that has you covered.

Justin Clarebert, a member of the Visual Studio team released the HotKeys Keyboard Shortcuts extension, which allows you to easily configure Visual Studio 2017 to use the keyboard shortcuts from those other popular editors and tools, giving you the productivity you are accustomed to within a new environment.

Okay. So this is another feature that isn’t directly built in to Visual Studio 2017, but it’s too big of a productivity enhancer to leave off this list (and since it’s not built it, I suppose it still qualifies as a “secret”).