Analog of CRM 4 methods CrmService.CreateAsync(UpdateAsync) in CRM 2011 - c#

Is it possible to make asyncs calls, like it was in Crm 4
crmService.UpdateAsync(card, Guid.NewGuid());
in CRM 2011???
I have to do synchronization between CRM and some system with the help of SSIS.
In destination script component I'd like to use Async calls, but I don't want to write async calls on my own.
Thank you!!!

I've mainly worked with CRM 2011 (as opposed to CRM 4) but it sounds like you're about to deploy a plugin. If not, stop reading now. :)
If you are, you can set the type of call to asynchronous while registering your plugin in the PRT. Just click for the option.
You've also got another option. If you're running the newest .NET framework, there's a new keyword - async that executes the method asynchronously. And if you're targeting an older .NET version, don't despair - I used threads for a lengthy update and that worked out quite well too.

It could be answer for this question, but it's possible only in CRM 2011 UR 12
#region Execute Multiple with Results
// Create an ExecuteMultipleRequest object.
requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
// Create several (local, in memory) entities in a collection.
EntityCollection input = GetCollectionOfEntitiesToCreate();
// Add a CreateRequest for each entity to the request collection.
foreach (var entity in input.Entities)
{
CreateRequest createRequest = new CreateRequest { Target = entity };
requestWithResults.Requests.Add(createRequest);
}
// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
// Display the results returned in the responses.
foreach (var responseItem in responseWithResults.Responses)
{
// A valid response.
if (responseItem.Response != null)
DisplayResponse(requestWithResults.Requests[responseItem.RequestIndex], responseItem.Response);
// An error has occurred.
else if (responseItem.Fault != null)
DisplayFault(requestWithResults.Requests[responseItem.RequestIndex],
responseItem.RequestIndex, responseItem.Fault);
}
Code from MSDN

Related

Manage a long-running operation in MS Teams Bot

I am using the following sample / article to Manage a Long-running operation in MS Teams Bot.
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-long-operations-guidance?view=azure-bot-service-4.0
In step 5, a DirectLineClient is being created and an Event Activity is sent to Bot using PostActivityAsync.
var responseActivity = new Activity("event");
responseActivity.Value = originalActivity;
responseActivity.Name = "LongOperationResponse";
responseActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
var directLineSecret = Environment.GetEnvironmentVariable("DirectLineSecret");
using(DirectLineClient client = new DirectLineClient(directLineSecret))
{
var conversation = await client.Conversations.StartConversationAsync();
await client.Conversations.PostActivityAsync(conversation.ConversationId, responseActivity);
}
However, I need the above sample to work for MS Teams Bot and not the DirectLineClient.
I used Microsoft.Bot.Connector.ConnectorClient but StartconversationAsync and PostActivityAsync methods are not available.
I tried the methods available in Microsoft.Bot.Connector.ConnectorClient
connectorClient.Conversations.CreateConversationAsync(conversationparameters)
connectorClient.ConversationsCreateDirectConversationAsync(botAccount, userAccount, (Activity)newActivity);
connectorClient.Conversations.SendToConversationAsync(conversationid, (Activity)newActivity);
But all the methods failed with Bad Requestwith the error as seen in the Response:
{"error":{"code":"BadArgument","message":"Unknown activity type"}}
The newActivity is created as below:
var messagnewActivity = new Activity("event");
newActivity.Value = originalActivity;
newActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
newActivity.Type = "event";
newActivity.Conversation = new ConversationAccount { Id = originalActivity.Conversation.Id };
newActivity.ChannelId = originalActivity.ChannelId;
Can someone please suggest how do I pass the Activity (Event Activity type) to MS Teams Bot.
Thanks
Gagan
I'm not really familiar with Direct Line, but I think it's effectively an -alternative- type of bot to Teams, so if you're trying to do this inside Teams, it explains the issue. In principle, the basic idea is quite simple though:
you store state somehow (e.g. in memory or in a database) to indicate that the long running operation is in progress for the user
when the long-running process is complete, your code (which could live OUTSIDE your bot, e.g. in an Azure Function) can send the user a message AS IF IT WAS the bot - this is called Pro-Active Messaging and you can read more about it at https://learn.microsoft.com/en-us/graph/teams-proactive-messaging.
This is to inform you that I was facing the same issue sometime before then I found a tweak in the code while debugging. when it calls twice recursively then the Activity Id is the same as the previous one. you can check if the activity id is the same then return the request else go with it.

Azure CosmosDB SDK v3 with ASP.NET Web Forms

I have an issue with the following code, working well in a Console App project and not working in a ASP.NET Web Forms project, both targeting .NET Framework 4.7.2.
The goal is to use the last Azure Cosmos DB SDK (v3) to get all documents in a container, without specifying a type (use of dynamic).
I've tried to target both the emulator (the last version 2.4.5) and the Azure Cosmos service.
In the ASP.NET project, the execution of queryResultSetIterator.ReadNextAsync().Result never ends (no timeout).
string endpointUri = "https://localhost:8081";
string primaryKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
string database = "SendGridEvents";
string collection = "SendGridEvents";
using (CosmosClient client = new CosmosClient(endpointUri, primaryKey))
{
Container container = client.GetDatabase(database).GetContainer(collection);
QueryDefinition queryDefinition = new QueryDefinition("SELECT * FROM c");
FeedIterator<dynamic> queryResultSetIterator = container.GetItemQueryIterator<dynamic>(queryDefinition);
List<dynamic> documents = new List<dynamic>();
while (queryResultSetIterator.HasMoreResults)
{
FeedResponse<dynamic> currentResultSet = queryResultSetIterator.ReadNextAsync().Result;
foreach (var document in currentResultSet)
{
documents.Add(document);
}
}
}
This is caused due to a deadlock because of the use of the problematic .Result.
There are countless of sources that explain this deadlock but I will link this answer from StackOverflow.
The TL;DR is that you are blocking an otherwise asynchronous call in the UI thread which is causing the deadlock. You need to properly await your call like this:
FeedResponse<dynamic> currentResultSet = await queryResultSetIterator.ReadNextAsync();
You could technically block the call if you used the ConfigureAwait(false) approach but the v3 SDK does not cascade this call all the way to the network calls so it wouldn't make any difference. WebForms allows you to have async handlers so you would be fine to make your method async and try again.

Dynamics CRM: CreateRequest concurrency issue

I am using MS Dynamics CRM SDK with C#. In this I have a WCF service method which creates an entity record.
I am using CreateRequest in the method. Client is calling this method with 2 identical requests one after other immediately.
There is a fetch before creating a record. If the record is available we are updating it. However, 2 inserts are happening at the exact time.
So 2 records with identical data are getting created in CRM.
Can someone help to prevent concurrency?
You should force the duplicate detection rule & decide what to do. Read more
Account a = new Account();
a.Name = "My account";
CreateRequest req = new CreateRequest();
req.Parameters.Add("SuppressDuplicateDetection", false);
req.Target = a;
try
{
service.Execute(req);
}
catch (FaultException<OrganizationServiceFault> ex)
{
if (ex.Detail.ErrorCode == -2147220685)
{
// Account with name "My account" already exists
}
else
{
throw;
}
}
As Filburt commented in your question, the preferred approach would be to use an Alternate Key and Upsert requests but unfortunately that's not an option for you if you're working with CRM 2013.
In your scenario, I'd implement a very lightweight cache in the WCF service, probably using the MemoryCache object from the System.Runtime.Caching.dll library (small example). Before executing the query to CRM, you can check if the record exists in the cache and continue with you current processing if it doesn't (remembering to add the record to the cache with a small expiration time for potential concurrent executions) or handle the scenario where the record already exists in the cache (and here you can go from having quite complex checks to detect and prevent potential data loss/unnecessary updates to a simple and stupid Thread.Sleep(1000)).

Calling wcf aync service in asp.net core 2.0 while waiting the result

I do understand that I might be getting this wrong since I am porting asp.net application to asp.net core 2.0 (mainly because the optimizations regarding load speed on pages) but I would ask the question anyway.
So my queries are working properly when I am fetching data only, however, I ran into a problem while having to fetch a file path from the database in order to download it on the client side. Since I don't need the whole model of the file I have 3 field dto on the client side that I fill up with the information regarding the file (etc location, size, filename) the problem is that when I send the async request toward the WCF service on Azure that's hold my entity framework link to the database the code continues further without waiting for the data to be retrieved from the database and throws null reference exception while attempting to fill the dto object that is to be sent further to the client in order to retrieve the file that's marked for downloading
This is my data access on the client side
internal async Task<AnimalDocument> GetAnimalDocument(int id)
{
var data = await _context.GetAnimalDocumentAsync(id);
var result = JsonConvert.DeserializeObject<AnimalDocument>(data);
return result;
}
And this is where I get the null exception
public SeriliazedFile GetFile(int id, int type)
{
var result = new SeriliazedFile();
if (type == 1)
{
var data = _context.GetHumanFile(id);
result.FileName = data.Result.DocumentName;
result.FilePath = data.Result.DocumentLocation;
result.FileSize = data.Result.FileSize.Value;
}
else if (type == 2)
{
var data = _context.GetAnimalDocument(id);
result.FileName = data.Result.DocumentName;
result.FilePath = data.Result.DocumentLocation;
result.FileSize = data.Result.FileSize.Value;
}
return result;
}
Is there a way to force the async request to wait for the result before returning Task that I retrieve from the WCF? I've tried telling _context.GetAnimalDocument(id).Wait(); however, nothing happens it still proceeds further without any result.I've noticed that the trigger to retrieve the data is fired after the ajax request that is sent toward the page returns 200 causing something like a deadlock but I might be wrong. If anyone could give me a work around it would be nice, I am pretty sure that I would figure it out on my own eventually but time is rare anyway, I hope you have a good day.
I am sorry for posting this, it was not a issue with the WCF or the code in any way, async works perfectly fine with asp.net core 2.0 the issue was with me. I am still adapting to the concept of have [FromBody] in front of the types in the functions, it appears to be that I missed one and I was getting id 0 by default (not that I can figure out why I would get 0 instead of null on integer field when there is no data but that doesn't matter anyway.) in my id field and the data layer was returning null value that's why I was getting null reference exception later.

How to track MongoDB requests from a console application

I have a Console Application project written in C# which I've added Application Insights to with the following NuGet packages.
Microsoft.ApplicationInsights
Microsoft.ApplicationInsights.Agent.Intercept
Microsoft.ApplicationInsights.DependencyCollector
Microsoft.ApplicationInsights.NLogTarget
Microsoft.ApplicationInsights.PerfCounterCollector
Microsoft.ApplicationInsights.Web
Microsoft.ApplicationInsights.WindowsServer
Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel
I've configured my InstrumentationKey in the config file and I'm firing up a TelemetryClient on startup using the with the following code:
var telemetryClient = new TelemetryClient();
telemetryClient.Context.User.Id = Environment.UserName;
telemetryClient.Context.Session.Id = Guid.NewGuid().ToString();
telemetryClient.Context.Device.OperatingSystem = Environment.OSVersion.ToString();
Everything is working well except AI is not capturing any requests that get sent to Mongo, I can see requests going off to SQL server in the 'Application map' but no sign of any other external requests. Is there any way that I can see telemetry of requests made to Mongo?
EDIT - Thanks to Peter Bons I ended up with pretty much the following which works like a charm and allows me to distinguish between success and failure:
var telemetryClient = new TelemetryClient();
var connectionString = connectionStringSettings.ConnectionString;
var mongoUrl = new MongoUrl(connectionString);
var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl);
mongoClientSettings.ClusterConfigurator = clusterConfigurator =>
{
clusterConfigurator.Subscribe<CommandSucceededEvent>(e =>
{
telemetryClient.TrackDependency("MongoDB", e.CommandName, DateTime.Now.Subtract(e.Duration), e.Duration, true);
});
clusterConfigurator.Subscribe<CommandFailedEvent>(e =>
{
telemetryClient.TrackDependency("MongoDB", $"{e.CommandName} - {e.ToString()}", DateTime.Now.Subtract(e.Duration), e.Duration, false);
});
};
var mongoClient = new MongoClient(mongoClientSettings);
I am not familiar with MongoDB but as far as I can tell there is no default support for it when it comes to Application Insights. But that does not mean you cannot do this, it will just involve some more code.
Again, I am not familiar with MongoDB but according to http://www.mattburkedev.com/logging-queries-from-mongodb-c-number-driver/ there is built-in support for logging the generated queries. Now, we only need to hook this up to Application Insights.
Since you already know how to use the TelemetryClient we can use the custom tracking methods provided by that class. See https://learn.microsoft.com/nl-nl/azure/application-insights/app-insights-api-custom-events-metrics for the available custom tracking methods.
All you need to do is to insert some code like this:
telemetryClient.TrackDependency(
"MongoDB", // The name of the dependency
query, // Text of the query
DateTime.Now, // Time that query is executed
TimeSpan.FromSeconds(0), // Time taken to execute query
true); // Indicates success
The class telemetryClient is thread-safe so you can reuse it.
Now, according to the referenced blogpost you should be able to do something like this:
var client = new MongoClient(new MongoClientSettings()
{
Server = new MongoServerAddress("localhost"),
ClusterConfigurator = cb =>
{
cb.Subscribe<CommandStartedEvent>(e =>
{
telemetryClient.TrackDependency(
"MongoDB", // The name of the dependency
e.Command.ToJson() // Text of the query
DateTime.Now, // Time that query is executed
TimeSpan.FromSeconds(0), // Time taken to execute query
true); // Indicates success
});
}
});
Again, I am not familiar with MongoDB but I hope this is a starting point for your imagination on how to adapt it to your needs using your knowledge of MongoDB.
EDIT:
If there is also a CommandCompletedEvent or similar event as opposed to the CommandStartedEvent event you should probably track the dependency there because you should then be able to calculate (or simpel read) the time spent and maybe get the actual value for the success indicator.

Categories

Resources