InvalidOperationException on Asp .Net Core - multithreading

i am getting this error when i am calling this function:
InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext.
I don't know what the problem is.
public async Task<bool> sendFirstOrderNotification(Order order)
{
var users = getUsersWithrole("Admin");
foreach (var user in users)
{
if (!string.IsNullOrEmpty(user.NotificationToken))
{
var notificationPayload = new FirebaseNotificationPayload()
{
Title = user.Name,
Body = order.Id + "رقم الطلب " + "بإجراء طلب لأول مرة " + "قام مستخدم ",
};
string response = SendNotification(notificationPayload, user.NotificationToken).Result;
Create(new NotificationLog()
{
CreatedDate = DateTime.Now,
Id = 0,
OrderId = order.Id,
Token = user.NotificationToken,
UserId = user.Id,
NotificationJson = JsonConvert.SerializeObject(notificationPayload),
ResponseJson = response
});
}
}
return true;
}
can anyone tell me what's causing the problem

Related

Getting 405 status Error when trying to consume POST method of web/Api in asp.net mvc5

I am trying to consume post method of web/api which takes string as parameter, but getting 405 Error : Api Controller Name: Getdata Action Method Name : postdata
please help to identify error.
public bool postdata(string fn)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:59968/api/Getdata");
var task = client.PostAsJsonAsync("Getdata", fn);
task.Wait();
var res = task.Result;
if(res.IsSuccessStatusCode)
{
return true;
}
}
return false;
}
[HttpPost]
public IHttpActionResult postdata(string p)
{
using (var context = new MediaEntities())
{
mediatable m = new mediatable()
{
media_path = p,
is_active = true
};
context.mediatable.Add(m);
context.SaveChanges();
return Ok();
}
}
I think you have used action method names instead of controller name else provide details of your api.
client.BaseAddress = new Uri("http://localhost:59968/api/{controller_name}");
//HTTP POST
var postTask = client.PostAsJsonAsync("controller_name", fn);
This link might help you.

Azure table storage API inconsistent replies

I have an http-triggered azure function that receives a zip code. It then queries an Azure Table using the table API and retrieves the city, state, etc. The table contains zip/postal codes for US and CAN so there's about a million rows. When I send a request it returns the correct value the first time but if I keep sending it over and over it randomly switches between returning the record and returning an empty set. So it's not failing, and I'm not getting any kind of error like a timeout.
here is an example of a successful reply:
{
odata.metadata: "https://storageaccount###.table.core.windows.net/$metadata#Table###",
value: [
{
odata.etag: "W/"datetime'2019-10-18T16%3A02%3A26.9420514Z'"",
PartitionKey: "Portsmouth",
RowKey: "00210",
Timestamp: "2019-10-18T16:02:26.9420514Z",
AreaCode: "603",
City: "Portsmouth",
Country: "US",
Pref: "P",
State: "NH",
Zip: "00210"
}
]
}
and here is an empty one after pressing F5 after getting above reply:
{
odata.metadata: "https://storageaccount###.table.core.windows.net/$metadata#Table###",
value: [ ]
}
And then if I keep pressing F5 sometimes I get the record and sometimes I don't.
here are the table api url parameters (SAS-minus the signature)
?$filter=RowKey eq '00210' and Country eq 'US'
&sv=2019-02-02
&ss=t
&srt=sco
&sp=r
&se=2099-10-18T05:27:30Z
&st=2019-10-17T21:27:30Z
&spr=https
Does anyone know why it's behaving this way or what I could look into to figure it out?
According to this page there is a 5 second timeout for querying azure tables
(https://learn.microsoft.com/en-us/rest/api/storageservices/query-timeout-and-pagination). but when I look at the headers in postman I don't see any tokens.
postman results: https://i.stack.imgur.com/hReDM.png
full CORRECTED code
public static async Task<string> Run(HttpRequest req, ILogger log)
{
log.LogInformation("Start time = "+ DateTime.Now);
string apiResponse = "";
string zip = req.Query["zip"];
if(string.IsNullOrEmpty(zip)){return "No zip code found - please provide a url parameter in the format 'zip=[code]'";}
string apiBaseUrl = "https://***storage.table.core.windows.net/zip**?";
string queryFilter = "$first&$filter=RowKey eq '" + zip + "'";
//generate auth url in storage account in Azure
string authorization = "&sv=2019-02-02&ss=t&srt=sco&sp=r&se=2099-10-18T00:38:11Z&st=2019-10-17T16:38:11Z&spr=https&sig=7S%2BkaiTwGsZIkL***";
Regex rx_US = new Regex(#"^\d{5}$");
Regex rx_CA = new Regex(#"^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$");
if (rx_US.IsMatch(zip))
{
queryFilter = queryFilter + " and Country eq 'US'";
}
else if (rx_CA.IsMatch(zip))
{
//the table search is case sensitive - test for common errors
zip = zip.ToUpper(); //make all upper case
Regex rx_CA1 = new Regex(#"^[A-Z]\d[A-Z]-\d[A-Z]\d$"); //dash
Regex rx_CA2 = new Regex(#"^[A-Z]\d[A-Z]\d[A-Z]\d$"); //no space
if (rx_CA1.IsMatch(zip)){zip = zip.Replace("-", " ");}
if (rx_CA2.IsMatch(zip)){zip = zip.Insert (3, " ");}
queryFilter = "$single&$filter=RowKey eq '" + zip + "'" + " and Country eq 'CA'";
}
string queryUrl = apiBaseUrl + queryFilter + authorization;
try
{
var httpWebRequest = WebRequest.Create(queryUrl);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Headers.Add("Accept","application/json"); //if this is omitted you will get xml format
httpWebRequest.Method = "GET";
var httpResponse = await httpWebRequest.GetResponseAsync();
using(var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
apiResponse = responseText;
log.LogInformation("Full Table Response = " + responseText);
}
int i = 0;
while (httpResponse.Headers["x-ms-continuation-NextPartitionKey"] != null && apiResponse.Length < 105)
{
//if response is > 105 then it found something - don't keep looking
//if there are continuation tokens then keep querying until you find something
var partitionToken = httpResponse.Headers["x-ms-continuation-NextPartitionKey"];
var rowToken = httpResponse.Headers["x-ms-continuation-NextRowKey"];
var continuationUrl = "NextPartitionKey="+partitionToken+"&NextRowKey="+rowToken+"&";
queryUrl = apiBaseUrl + continuationUrl + queryFilter + authorization;
log.LogInformation("begin new httpRequest...");
httpWebRequest = WebRequest.Create(queryUrl);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Headers.Add("Accept","application/json");
httpWebRequest.Method = "GET";
httpResponse = await httpWebRequest.GetResponseAsync();
using(var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
apiResponse = responseText;
log.LogInformation("Full Table Response = " + responseText);
}
i++;
log.LogInformation("loop # "+ i + " - url = " + queryUrl + " Response = "+ apiResponse);
}
if(apiResponse.Length > 105)
{
//strip out extra data
apiResponse = apiResponse.Remove(1,101);
apiResponse = apiResponse.Remove(apiResponse.Length - 2,2);
}
else
{
apiResponse = "No data found for zip = " + zip + " - Ensure you have proper format and case";
}
}
catch (Exception ex)
{
apiResponse = "error: " + ex.Message;
}
log.LogInformation("ZipPostal function completed and returned "+ apiResponse);
return apiResponse;
}

How to get Logic App Metrics?

I'm trying to get Logic Apps metrics like BillableExecutions, Latency etc in my console application.
Currently I'm able to list the logic apps runs, triggers, versions using the .Net Client Microsoft.Azure.Management. But it doesn't seem to have the API to access the monitoring API's.
Code excerpt
private static void Main(string[] args)
{
var token = GetTokenCredentials();
var client = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (client)
{
var logicAppsWorkFlows = client.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
var runs = GetWorkflowRuns(client, logicAppsWorkFlow.Id.Split('/')[4], logicAppsWorkFlow.Name);
Console.WriteLine(runs.Count);
}
Console.WriteLine(logicAppsWorkFlows.Count());
}
}
Can someone tell me how to access Logic Apps Metrics? Is there a client similar to Microsoft.Azure.Management for access metrics data?
Update 2
I have found a client dll which was in pre release mode which is used to get metrics. Below is my current code
var token = GetTokenCredentials();
var insightsClient = new InsightsClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var logicManagementClient = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "name.value eq 'ActionLatency' and startTime ge '2014-07-16'"
};
IEnumerable<Metric> metricsList = null;
try
{
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}
I'm getting an exception saying the filter string is not valid. Im referring the filter string structure provided here
https://learn.microsoft.com/en-us/rest/api/monitor/filter-syntax
Can someone tell what im doing wrong here?
Thanks
It looks like ge is not allowed for Logic Apps StartTime field for some reason. I had to change the code to below to make it work
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "startTime eq " + DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd") + " and name.value eq 'BillableTriggerExecutions' and endTime eq " + DateTime.Now.ToString("yyyy-MM-dd")
};
var query = metricsDataQuery.GetQueryString();
Console.WriteLine(query);
IEnumerable<Metric> metricsList = null;
try
{
//throws exception if there is no metrics data
//TODO: Check whether the logic app ran atleast one time
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}

Why am I unable to list all my accounts with this code?

This is my first foray into Google Analytics. I created a service account and downloaded the p12 file from the developer console.
This code works, but in an incomplete way.
I have two accounts, but the code below just returns one account from the list.
How do I get all my accounts listed?
private static ServiceAccountCredential Run2()
{
const string keyfilePath = "file.p12";
const string serviceAccountMail = "notarealemailaddress#developer.gserviceaccount.com";
var certificate = new X509Certificate2(keyfilePath, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountMail)
{
Scopes = new[] { AnalyticsService.Scope.Analytics, AnalyticsService.Scope.AnalyticsReadonly, AnalyticsService.Scope.AnalyticsProvision }
}.FromCertificate(certificate));
return credential;
}
static void Main()
{
var cr = Run2();
var service = new AnalyticsService(new BaseClientService.Initializer()
{
HttpClientInitializer = cr,
ApplicationName = "Analytics API Sample"
});
var request = service.Management.Accounts.List();
request.MaxResults = 20;
var result = request.Execute();
foreach (var item in result.Items)
{
Console.WriteLine("Account Name: {0} {1} {2}", item.Name, item.Kind, item.Id);
}
}
This is what I ended up doing. The service account that Google creates needs to be added to every account that you need to access. I figured this from reading the documentation.
https://developers.google.com/analytics/devguides/config/mgmt/v3/quickstart/service-py
Try this out
ManagementResource.AccountSummariesResource.ListRequest list = service.Management.AccountSummaries.List();
list.MaxResults = 1000; // Maximum number of Account Summaries to return per request.
AccountSummaries feed = list.Execute();
List allRows = new List();
//// Loop through until we arrive at an empty page
while (feed.Items != null)
{
allRows.AddRange(feed.Items);
// We will know we are on the last page when the next page token is
// null.
// If this is the case, break.
if (feed.NextLink == null)
{
break;
}
// Prepare the next page of results
list.StartIndex = feed.StartIndex + list.MaxResults;
// Execute and process the next page request
feed = list.Execute();
}
feed.Items = allRows;
//Get account summary and display them.
foreach (AccountSummary account in feed.Items)
{
// Account
Console.WriteLine("Account: " + account.Name + "(" + account.Id + ")");
foreach (WebPropertySummary wp in account.WebProperties)
{
// Web Properties within that account
Console.WriteLine("\tWeb Property: " + wp.Name + "(" + wp.Id + ")");
//Don't forget to check its not null. Believe it or not it could be.
if (wp.Profiles != null)
{
foreach (ProfileSummary profile in wp.Profiles)
{
// Profiles with in that web property.
Console.WriteLine("\t\tProfile: " + profile.Name + "(" + profile.Id + ")");
}
}
}
}
Reference: http://www.daimto.com/googleanalytics-management-csharp/
http://www.daimto.com/googleAnalytics-authentication-csharp/

Send email using Office 365 using unified API

We are trying to use the O365 Unified API to send emails from our line-of-business apps. I use the following code to send the email. This throws a DataServiceQueryException exception "Unauthorized".
public async Task SendEmailAsUserAsync(EmailMessage message)
{
try
{
var graphClient = await _authenticationHelper.GetGraphClientAsync();
Message m = InitializeMessage(message);
await graphClient.Me.SendMailAsync(m, true);
}
catch (DataServiceQueryException dsqe)
{
_logger.Error("Could not get files: " + dsqe.InnerException.Message, dsqe);
throw;
}
}
private static Message InitializeMessage(EmailMessage message)
{
ItemBody body = new ItemBody {Content = message.Body, ContentType = BodyType.HTML};
Message m = new Message
{
Body = body,
Subject = message.Subject,
Importance = Importance.Normal,
};
//Add all the to email ids
if (message.ToRecipients != null)
foreach (Models.Messaging.EmailAddress emailAddress in message.ToRecipients)
{
m.ToRecipients.Add(new Recipient { EmailAddress = new Microsoft.Graph.EmailAddress { Address = emailAddress.Address, Name = emailAddress.Name } });
}
return m;
}
The code for _authenticationHelper.GetGraphClientAsync() is
public async Task<GraphService> GetGraphClientAsync()
{
Uri serviceRoot = new Uri(appConfig.GraphResourceUriBeta + appConfig.Tenant);
_graphClient = new GraphService(serviceRoot,
async () => await AcquireTokenAsyncForUser(appConfig.GraphResourceUri, appConfig.Tenant));
return _graphClient;
}
private async Task<string> AcquireTokenAsyncForUser(string resource, string tenantId)
{
AuthenticationResult authenticationResult = await GetAccessToken(resource, tenantId);
_accessCode = authenticationResult.AccessToken;
return _accessCode;
}
private async Task<AuthenticationResult> GetAccessToken(string resource, string tenantId)
{
string authority = appConfig.Authority;
AuthenticationContext authenticationContext = new AuthenticationContext(authority);
ClientCredential credential = new ClientCredential(appConfig.ClientId, appConfig.ClientSecret);
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
string userAccessToken = authHeader.Substring(authHeader.LastIndexOf(' ')).Trim();
UserAssertion userAssertion = new UserAssertion(userAccessToken);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resource, credential, userAssertion);
return authenticationResult;
}
However if I change the SendEmailAsUserAsync method as shown below, the email is sent but an InvalidOperationException is thrown with message "The complex type 'System.Object' has no settable properties."
public async Task SendEmailAsUserAsync(EmailMessage message)
{
try
{
var graphClient = await _authenticationHelper.GetGraphClientAsync();
Message m = InitializeMessage(message);
//await graphClient.Me.SendMailAsync(m, true); //This did not work
var user = await graphClient.Me.ExecuteAsync();
await user.SendMailAsync(m, true);
}
catch (DataServiceQueryException dsqe)
{
_logger.Error("Could not get files: " + dsqe.InnerException.Message, dsqe);
throw;
}
}
Can any one point out if there is something wrong here.
Check the example project below, this has a working example (after you fill in the ClientID etc. in app.config).
Office 365 API demo applications
For sending email it uses the function below, which works if you set it up correctly. It also has a number of functions for Authenticating using Authorization Code Grant Flow.
public async Task SendMail(string to, string subject, string body)
{
var client = await this.AuthenticationHelper
.EnsureOutlookServicesClientCreatedAsync(
Office365Capabilities.Mail.ToString());
Message mail = new Message();
mail.ToRecipients.Add(new Recipient()
{
EmailAddress = new EmailAddress
{
Address = to,
}
});
mail.Subject = subject;
mail.Body = new ItemBody() { Content = body, ContentType = BodyType.HTML };
await client.Me.SendMailAsync(mail, true);
}
Actually, there is no assembly wrapper for the graph API.
Microsoft.Graph.dll is deprecrated.
So, you should to :
Deal with the REST requests : See here : http://graph.microsoft.io/docs/api-reference/v1.0/api/message_send
Generate a wrapper with Microsoft.Vipr project : see here : https://github.com/microsoft/vipr
For the authentication, ADAL works fine :)

Resources