I'm hoping someone can help me with this issue. I have two methods that insert a document into a Cosmos DB. One works each and every time I run it. The other gets as far as CreateDatabaseIfNotExistsAsync and kicks out of the method and returns to the calling method. The ItemReponse objects Status property says "WaitingForActivation".
I will say that this logic did work once and now (with no changes) it does not. Below is the code that dies. First the Unit test:
public void AddPerson()
{
var logger = Mock.Of<ILogger<Person>>();
var appset = Mock.Of<IAppSettings>();
appset.DatabaseName = "PersonsDB";
appset.ContainerName = "PersonsContainer";
appset.EndpointUrl = "https://localhost:8081";
appset.AuthorizationKey = "somesecretkey";
Person person = new Person()
{
id = Guid.NewGuid().ToString(),
Address_line_1 = "1932 Alakea St",
Address_line_2 = "",
Birth_Date = "2020-01-01",
Gender = "m",
Patient_First_Name = "John",
Patient_Last_Name = "Ridley",
Hospital_Code = "Queens Med",
Rec_ID = "1111111111",
VER_CRM_ID = "22222222",
VER_EMAIL = "JR#noemail.com",
};
PersonCosmos personCosmos = new PersonCosmos(logger, appset);
var myresult = personCosmos.PutPersonData(person);
Assert.True(myresult.Exception == null, "Row added");
}
Let me add that I am running the Cosmos Emulator hence the localhost url. Now for the code that dies.
public async Task<ItemResponse<Person>> PutPersonData(Person persondata)
{
this.cosmosClient = new CosmosClient(EndpointUri, PrimaryKey);
this.database = await this.cosmosClient.CreateDatabaseIfNotExistsAsync(DatabaseName);
this.container = await this.database.CreateContainerIfNotExistsAsync(ContainerName, "/Hospital_Code");
ItemResponse<Person> PutResponse = null;
try
{
// Read the item to see if it exists.
PutResponse = await this.container.ReadItemAsync<Person>(persondata.id.ToString(), new PartitionKey(persondata.Hospital_Code ));
return PutResponse;
}
catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
// Create an item in the container representing the Appointment. Note we provide the value of the partition key for this item, which is "Hospital_Code"
PutResponse = await this.container.CreateItemAsync<Person>(persondata, new PartitionKey(persondata.Hospital_Code));
return PutResponse;
}
catch (Exception ex)
{
// Create an item in the container representing the object. Note we provide the value of the partition key for this item, which is "Hospital_Code"
_logger.LogError($"Error in {0} at {1} " + ex.Message, System.Reflection.MethodBase.GetCurrentMethod().Name, DateTime.UtcNow.ToLongTimeString());
return PutResponse;
}
}
You are mixing sync and async in your code here.
Use await on this line.
var myresult = **await** personCosmos.PutPersonData(person);
and also this calling function should be async as well
public void AddPerson()
Related
My telegram bot is necessary so that the user can answer questions in order and save these answers in the same order for a specific user in parallel.
static readonly ConcurrentDictionary<int, string[]> Answers = new ConcurrentDictionary<int, string[]>();
static void Main(string[] args)
{
try
{
Task t1 = CreateHostBuilder(args).Build().RunAsync();
Task t2 = BotOnMessage();
await Task.WhenAll(t1, t2);
}
catch (Exception ex)
{
Console.WriteLine("Error" + ex);
}
}
here is my BotOnMessage() method to receive and process messages from users
async static Task BotOnMessage()
{
int offset = 0;
int timeout = 0;
try
{
await bot.SetWebhookAsync("");
while (true)
{
var updates = await bot.GetUpdatesAsync(offset, timeout);
foreach (var update in updates)
{
var message = update.Message;
if (message.Text == "/start")
{
Registration(message.Chat.Id.ToString(), message.Chat.FirstName.ToString(), createdDateNoTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture));
var replyKeyboard = new ReplyKeyboardMarkup
{
Keyboard = new[]
{
new[]
{
new KeyboardButton("eng"),
new KeyboardButton("ger")
},
}
};
replyKeyboard.OneTimeKeyboard = true;
await bot.SendTextMessageAsync(message.Chat.Id, "choose language", replyMarkup: replyKeyboard);
}
switch (message.Text)
{
case "eng":
var replyKeyboardEN = new ReplyKeyboardMarkup
{
Keyboard = new[]
{
new[]
{
new KeyboardButton("choice1"),
new KeyboardButton("choice2")
},
}
};
replyKeyboardEN.OneTimeKeyboard = true;
await bot.SendTextMessageAsync(message.Chat.Id, "Enter choice", replyMarkup: replyKeyboardEN);
await AnonymEN();
break;
case "ger":
var replyKeyboardGR = new ReplyKeyboardMarkup
{
Keyboard = new[]
{
new[]
{
new KeyboardButton("choice1.1"),
new KeyboardButton("choice2.2")
},
}
};
replyKeyboardGR.OneTimeKeyboard = true;
await bot.SendTextMessageAsync(message.Chat.Id, "Enter choice", replyMarkup: replyKeyboardGR);
await AnonymGR();
break;
}
offset = update.Id + 1;
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error" + ex);
}
}
and AnonymEN() method for eng case in switch. The problem appears here when I call this method from switch case in BotOnMessage(). Until switch (message.Text) multiple users can asynchronously send messages and get response. When first user enters AnonymEN() second user can't get response from this method until first user will finish it till the end. Also I call BotOnMessage() in the end of AnonymEN() to get back for initial point with possibility to start bot again. For the ordered structure of questions and answers I used ConcurrentDictionary way from here Save user messages sent to bot and send finished form to other user. Any suggestion and solution how to edit code to make this bot available for multiple users at one time?
async static Task AnonymEN()
{
int offset = 0;
int timeout = 0;
try
{
await bot.SetWebhookAsync("");
while (true)
{
var updates = await bot.GetUpdatesAsync(offset, timeout);
foreach (var update in updates)
{
var message = update.Message;
int userId = (int)message.From.Id;
if (message.Type == MessageType.Text)
{
if (Answers.TryGetValue(userId, out string[] answers))
{
var title = message.Text;
if (answers[0] == null)
{
answers[0] = message.Text;
await bot.SendTextMessageAsync(message.Chat, "Enter age");
}
else
{
SaveMessage(message.Chat.Id.ToString(), "anonym", "anonym", "anonym", answers[0].ToString(), title.ToString(), createdDateNoTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture));
Answers.TryRemove(userId, out string[] _);
await bot.SendTextMessageAsync(message.Chat.Id, "ty for request click /start");
await BotOnMessage();
}
}
else if (message.Text == "choice1")
{
Answers.TryAdd(userId, new string[1]);
await bot.SendTextMessageAsync(message.Chat.Id, "Enter name");
}
}
offset = update.Id + 1;
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error" + ex);
}
}
I can see multiple issues with your code:
It is hard to read. While this is a personal preference I strongly advise to write short concise methods that have 1 responsibility. This will make it easier to understand and maintain your code. https://en.wikipedia.org/wiki/Single-responsibility_principle
Everything is static. This makes it very hard to keep track of any state such as language that should be tracked per user.
Using infinite loops and recursion with no escape. I highly doubt this was intended but you could get an infinite chain of calls like this BotOnMessage -> AnonymEN -> BotOnMessage -> AnonymEN. I think you want to exit the AnonymEN function using either a return, break or while(someVar) approach instead of calling the BotOnMessage function.
If two users are sending messages you get mixed responses. Example message flow user1: /start, user1: eng, user2: hello. The bot will now give an english response to user2. I'm sure this is not intended
The code below is a minimal example that addresses the issues I mentioned. It is not perfect code but should help you get started.
private Dictionaty<string, UserSession> userSessions = new ();
async Task BotOnMessage()
{
try
{
while(true)
{
var message = await GetMessage(timeout);
var userSession = GetUserSession(message.user);
userSession.ProcessMessage(message);
}
}
catch(){}
}
async void GetUserSession(string user)
{
if(!userSessions.HasKey(user))
{
userSessions[user](new Session());
}
return userSessions[user];
}
public class UserSession
{
public async Task ProcessMessage(message)
{
// Existing message processing code goes here.
// Do not use a loop or recursion.
// Instead track the state (e.g. languge) using fields.
}
}
I am trying to update the AmoutMicros of Budget but I don't receive error, just not update the budget:
CampaignBudget budget = new CampaignBudget()
{
ResourceName = ResourceNames.CampaignBudget(customerId, budgetId),
AmountMicros = (price + amount) * 100000,
Id = budgetId
};
CampaignBudgetOperation budgetOperation = new CampaignBudgetOperation()
{
Create = budget,
UpdateMask = FieldMasks.AllSetFieldsOf(budget),
};
try
{
MutateCampaignBudgetsResponse responseBudget =
budgetService.MutateCampaignBudgets(
customerId.ToString(), new CampaignBudgetOperation[] { budgetOperation
});
foreach(MutateCampaignBudgetResult result in responseBudget.Results)
{
updateResponse.CampignId = campaignId;
updateResponse.Updated = true;
Console.WriteLine(result);
}
return updateResponse;
}
catch (GoogleAdsException e)
{
Console.WriteLine("Failure:");
Console.WriteLine($"Message: {e.Message}");
Console.WriteLine($"Failure: {e.Failure}");
Console.WriteLine($"Request ID: {e.RequestId}");
return updateResponse;
throw;
}
This code don't show me a exception, apparently it was update, but, when I go at Google Ads Dashboard, the amout still the same.
I read the documentation but I didn't find an update of a budget.
My working code is PHP but you can refer this.
private static function updateCampaignBudget(GoogleAdsClient $googleAdsClient, int $customerId,int $campaign_budget,string $budget_resource_name){
// Creates a campaign budget.
$budget = new CampaignBudget([
'resource_name' => $budget_resource_name,
//'delivery_method' => BudgetDeliveryMethod::STANDARD,
'amount_micros' => $campaign_budget
//'explicitly_shared' => false
]);
// Creates a campaign budget operation.
$campaignBudgetOperation = new CampaignBudgetOperation();
$campaignBudgetOperation->setUpdate($budget);
$campaignBudgetOperation->setUpdateMask(FieldMasks::allSetFieldsOf($budget));
// Issues a mutate request.
$campaignBudgetServiceClient = $googleAdsClient->getCampaignBudgetServiceClient();
$response = $campaignBudgetServiceClient->mutateCampaignBudgets(
$customerId,
[$campaignBudgetOperation]
);
/** #var CampaignBudget $addedBudget */
$updatedBudget = $response->getResults()[0];
//printf("Added budget named '%s'%s", $addedBudget->getResourceName(), PHP_EOL);
return $updatedBudget->getResourceName();
}
you can use ResourceNames::forCampaignBudget(customerId, budgetId) instead of $budget_resource_name
I am trying to update EmploymentEndDate in Contract in D365 Finance and Operation with oData using DataServiceCollection.
There is no error and it seems everything went well, but in the Contract EmploymentEndDate has no changes.
Similar code working well for other entities as Workers, Employee etc...
Has anyone experienced a similar situation, or to suggest other solution for this problem?
Thank You
public bool UpdateContractNG(string pPersonnelNumber, DateTime pEndEmploymentDate)
{
try
{
Resources _contextUpd = Queries365.CreateErpContext();
var queryUpd = from Employment
in _contextUpd.Employments
where Employment.PersonnelNumber == pPersonnelNumber
orderby Employment.EmploymentStartDate descending
select Employment;
DataServiceCollection<Employment> employmentCollection = new DataServiceCollection<Employment>(queryUpd);
if (employmentCollection != null)
{
foreach (Employment emp in employmentCollection)
{
Console.WriteLine($"OLD EMPLOYMENT: {JsonConvert.SerializeObject(emp)}");
emp.EmploymentEndDate = pEndEmploymentDate.ToUniversalTime();
_contextUpd.UpdateObject(emp);
Console.WriteLine($"IN MEMORY CHANGED EMPLOYMENT: {JsonConvert.SerializeObject(emp)}");
break;
}
}
DataServiceResponse response = _contextUpd.SaveChanges(SaveChangesOptions.PostOnlySetProperties);
// for testing (same context Check)
Employment emp2 = Queries365.GetContract(_contextUpd, pPersonnelNumber);
Console.WriteLine($"FROM SAME CONTEXT EMPLOYMENT: {JsonConvert.SerializeObject(emp2)}");
// new context refreshed data
Resources _newContext = Queries365.CreateErpContext();
Employment empAfterNew = Queries365.GetContract(_newContext, pPersonnelNumber);
Console.WriteLine($"AFTER UPDATE NEW CONTEXT: {JsonConvert.SerializeObject(empAfterNew)}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Error updating contract with Id {pPersonnelNumber} with Exception: {ex} ");
return false;
}
}
public static Resources CreateErpContext()
{
// Resource
string ODataEntityPath = ClientConfiguration.Default.UriString + "data";
Uri oDataUri = new Uri(ODataEntityPath, UriKind.Absolute);
Resources context = new Resources(oDataUri);
context.SendingRequest2 += new EventHandler<SendingRequest2EventArgs>(delegate (object sender, SendingRequest2EventArgs e)
{
var authenticationHeader = OAuthHelper.GetAuthenticationHeader(useWebAppAuthentication: true);
e.RequestMessage.SetHeader(OAuthHelper.OAuthHeader, authenticationHeader);
});
return context;
}
public static Employment GetContract(Resources context, string personnelNumber)
{
Employment emp = context.Employments.Where(x => x.PersonnelNumber == personnelNumber)
.OrderByDescending(x => x.EmploymentStartDate).FirstOrDefault();
return emp;
}
The output line:
Console.WriteLine($"AFTER UPDATE NEW CONTEXT {JsonConvert.SerializeObject(empAfterNew)}");
returns unexpected value for end date: "EmploymentEndDate":"2019-12-31T23:00:00+00:00".
And it is not updated in the system D365 for Finance and Opereations
I have the following code.
[HttpGet]
public async Task<List<TenantManagementWebApi.Entities.SiteCollection>> Get()
{
var tenant = await TenantHelper.GetActiveTenant();
var siteCollectionStore = CosmosStoreFactory.CreateForEntity<TenantManagementWebApi.Entities.SiteCollection>();
await siteCollectionStore.RemoveAsync(x => x.Title != string.Empty); // Removes all the entities that match the criteria
string domainUrl = tenant.TestSiteCollectionUrl;
string tenantName = domainUrl.Split('.')[0];
string tenantAdminUrl = tenantName + "-admin.sharepoint.com";
KeyVaultHelper keyVaultHelper = new KeyVaultHelper();
await keyVaultHelper.OnGetAsync(tenant.SecretIdentifier);
using (var context = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(tenantAdminUrl, tenant.Email, keyVaultHelper.SecretValue))
{
Tenant tenantOnline = new Tenant(context);
SPOSitePropertiesEnumerable siteProps = tenantOnline.GetSitePropertiesFromSharePoint("0", true);
context.Load(siteProps);
context.ExecuteQuery();
List<TenantManagementWebApi.Entities.SiteCollection> sites = new List<TenantManagementWebApi.Entities.SiteCollection>();
foreach (var site in siteProps)
{
if(site.Template.Contains("SITEPAGEPUBLISHING#0") || site.Template.Contains("GROUP#0"))
{
string strTemplate= default(string);
if(site.Template.Contains("SITEPAGEPUBLISHING#0"))
{
strTemplate = "CommunicationSite";
};
if (site.Template.Contains("GROUP#0"))
{
strTemplate = "Modern Team Site";
};
try
{
Guid id = Guid.NewGuid();
Entities.SiteCollection sc = new Entities.SiteCollection()
{
Id = id.ToString(),
Owner = site.Owner,
Template = strTemplate,
Title = site.Title,
Active = false,
Url = site.Url
};
var added = await siteCollectionStore.AddAsync(sc);
sites.Add(sc);
}
catch (System.Exception ex)
{
throw ex;
}
}
}
return sites;
};
}
However the following lines, I am repeating them on every method:
var tenant = await TenantHelper.GetActiveTenant();
var siteCollectionStore = CosmosStoreFactory.CreateForEntity<TenantManagementWebApi.Entities.SiteCollection>();
await siteCollectionStore.RemoveAsync(x => x.Title != string.Empty); // Removes all the entities that match the criteria
string domainUrl = tenant.TestSiteCollectionUrl;
string tenantName = domainUrl.Split('.')[0];
string tenantAdminUrl = tenantName + "-admin.sharepoint.com";
KeyVaultHelper keyVaultHelper = new KeyVaultHelper();
await keyVaultHelper.OnGetAsync(tenant.SecretIdentifier);
I will have lots of API controllers on my project
Is there an easy way (not refactor as a method), to make my code cleaner and inject the variables I need without copying and pasting every single time?
I have written an app that goes through our own properties and scraps the data. To make sure I don't run through the same URLs, I am using a MySQL database to store the URL, flag it once its processed. All this was being done in a single thread and it's fine if I had only few thousand entries. But I have few hundred thousand entries that I need to parse so I need to make changes in the code (I am newbie in multithreading in general). I found an example and was trying to copy the style but doesn't seem to work. Anyone know what the issue is with the following code?
EDIT: Sorry didn't mean to make people guess the issue but was stupid of me to include the exception. Here is the exception
"System.InValidCastException: 'Specified cast is not valid.'"
When I start the process it collects the URLs from the database and then never hits DoWork method
//This will get the entries from the database
List<Mappings> items = bot.GetUrlsToProcess(100);
if (items != null)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Worker.Done = new Worker.DoneDelegate(WorkerDone);
foreach (var item in items)
{
urls.Add(item.Url);
WaitingTasks.Enqueue(new Task(id => new Worker().DoWork((int)id, item.Url, token), item.Url, token));
}
LaunchTasks();
}
static async void LaunchTasks()
{
// keep checking until we're done
while ((WaitingTasks.Count > 0) || (RunningTasks.Count > 0))
{
// launch tasks when there's room
while ((WaitingTasks.Count > 0) && (RunningTasks.Count < MaxRunningTasks))
{
Task task = WaitingTasks.Dequeue();
lock (RunningTasks) RunningTasks.Add((int)task.AsyncState, task);
task.Start();
}
UpdateConsole();
await Task.Delay(300); // wait before checking again
}
UpdateConsole(); // all done
}
static void UpdateConsole()
{
Console.Write(string.Format("\rwaiting: {0,3:##0} running: {1,3:##0} ", WaitingTasks.Count, RunningTasks.Count));
}
static void WorkerDone(int id)
{
lock (RunningTasks) RunningTasks.Remove(id);
}
public class Worker
{
public delegate void DoneDelegate(int taskId);
public static DoneDelegate Done { private get; set; }
public async void DoWork(object id, string url, CancellationToken token)
{
if (token.IsCancellationRequested) return;
Content obj;
try
{
int tries = 0;
bool IsUrlProcessed = true;
DateTime dtStart = DateTime.Now;
string articleDate = string.Empty;
try
{
ScrapeWeb bot = new ScrapeWeb();
SearchApi searchApi = new SearchApi();
SearchHits searchHits = searchApi.Url(url, 5, 0);
if (searchHits.Hits.Count() == 0)
{
obj = await bot.ReturnArticleObject(url);
if (obj.Code != HttpStatusCode.OK)
{
Console.WriteLine(string.Format("\r Status is {0}", obj.Code));
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.HttpCode = obj.Code;
}
else
{
string title = obj.Title;
string content = obj.Contents;
string description = obj.Description;
Articles article = new Articles();
article.Site = url.GetSite();
article.Content = content;
article.Title = title;
article.Url = url.ToLower();
article.Description = description;
string strThumbNail = HtmlHelper.GetImageUrl(url, obj.RawResponse);
article.Author = HtmlHelper.GetAuthor(url, obj.RawResponse);
if (!string.IsNullOrEmpty(strThumbNail))
{
//This condition needs to be added to remove ?n=<number> from EP thumbnails
if (strThumbNail.Contains("?"))
{
article.ImageUrl = strThumbNail.Substring(0, strThumbNail.IndexOf("?")).Replace("http:", "https:");
}
else
article.ImageUrl = strThumbNail.Replace("http:", "https:");
}
else
{
article.ImageUrl = string.IsNullOrEmpty(strThumbNail) ? article.Url.GetDefaultImageUrls() : strThumbNail.Replace("http:", "https:");
}
articleDate = HtmlHelper.GetPublishDate(url, obj.RawResponse);
if (string.IsNullOrEmpty(articleDate))
article.Pubdate = DateTime.Now;
else
article.Pubdate = DateTime.Parse(articleDate);
var client = new Index(searchApi);
var result = client.Upsert(article);
itemfound.HttpCode = obj.Code;
if (result)
{
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate);
UpdateItem(itemfound);
}
else
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
UpdateItem(itemfound, tries, IsUrlProcessed);
}
}
}
else
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = true;
itemfound.HttpCode = HttpStatusCode.OK;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
}
}
catch (Exception e)
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
}
finally
{
DateTime dtEnd = DateTime.Now;
Console.WriteLine(string.Format("\r Total time taken to process items is {0}", (dtEnd - dtStart).TotalSeconds));
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Done((int)id);
}
}
All this code is based from Best multi-thread approach for multiple web requests this link. Can someone tell me how to get this approach running?
I think the problem is in the way you're creating your tasks:
new Task(id => new Worker().DoWork((int)id, item.Url, token), item.Url, token)
This Task constructor overload expected Action<object> delegate. That means id will be typed as object and you need to cast it back to something useful first.
Parameters
action
Type: System.Action<Object>
The delegate that represents the code to execute in the task.
state
Type: System.Object
An object representing data to be used by the action.
cancellationToken
Type: System.Threading.CancellationToken
-The CancellationToken that that the new task will observe.
You decided to cast it to int by calling (int)id, but you're passing item.Url as the object itself. I can't tell you 100% what the type of Url is but I don't expect Url-named property to be of type int.
Based on what #MarcinJuraszek said I just went back to my code and added an int as I couldn't find another way to resolve it. Here is the change I made
int i=0
foreach (var item in items)
{
urls.Add(item.Url);
WaitingTasks.Enqueue(new Task(id => new Worker().DoWork((string)id, item.Url, token), item.Url, token));
i++;
}