Sending email using SendGrid take long time - asp.net

I using SendGrid in asp.net mvc. I use this code to send email :
var myMessage = new SendGridMessage();
myMessage.From = new MailAddress("john#example.com");
myMessage.AddTo("testing#something.com");
myMessage.Subject = "Subject";
myMessage.Text = "testing";
var credentials = new NetworkCredential("*********#azure.com", "");
Web transportWeb = new Web(credentials);
await transportWeb.DeliverAsync(myMessage);
The problem is that the email take around 5 minutes to reach the destination. Is this the normal case ? if it is normal how can I decrease this time ?

Related

AzureKeyVault Integration AzureFunction and xamarin forms

I have a xamarin app --> azureFunction --->BlobStorage. so far so good.
The AzureFunction is set with AuthorizationLevel.Function.
I have set the azure function Managed identity "ON"
I have assigned a role to the BlobStorage (Blob data Contributor)
I can successfully call the function using postman using the function key.
I would like to store the functionKey in the KeyVault and call it from my mobile app
Question
As anybody got a walkthrough and snippet how to integrate the keyvault with a function key and call it from a mobile app (xamarin forms) c#?
I do not want to hardcode any keys in my mobile app.
I would be very grateful.Lots of googling and nothing.
thanks
Suppose your requirement is call the function from the code. Maybe you could refer to the below code.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("your Secret Identifier")
.ConfigureAwait(false);
string functionkey = secret.Value;
string functionhost = "https://your function.azurewebsites.net/api/function name";
var param = new Dictionary<string, string>() { { "code", functionkey } ,{ "name","george"} };
Uri functionurl = new Uri(QueryHelpers.AddQueryString(functionhost, param));
var request = (HttpWebRequest)WebRequest.Create(functionurl);
var response = (HttpWebResponse)request.GetResponse();
string responseString;
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
responseString = reader.ReadToEnd();
Console.WriteLine(responseString);
}
}

SendGrid - It's like it does not send email to the customer

It's like I have contact Sendrid to hear about how I may not send email.
That's because I need a username and password to be able to do that.
Sendgrid say on Twitter (PM)
For sending mail through SMTP, you will want to set your host to http://smtp.sendgrid.net . You can then use port 587, 2525 or 25 for TLS connections, and can use either your SendGrid username/password for authentication, or an API key generated on your account.
Code:
var resultMail = await _viewRenderService.RenderToStringAsync("~/Views/Templates/NewPassword.cshtml", viewModel);
var api = Environment.GetEnvironmentVariable("azure_xxxxxxx#azure.com");
var client = new SendGridClient(api);
var from = new EmailAddress("hello#hello.com", "J. Petersen");
var to = new EmailAddress("test#test.com", "Test");
var plainTextContent = Regex.Replace(resultMail, "<[^>]*>", "");
var msg = MailHelper.CreateSingleEmail(from, to, title, plainTextContent: plainTextContent,
htmlContent: null);
var resulta = client.SendEmailAsync(msg);
I have looked at Documentation on Sendgrid, and I do not think I'll find that you need to use username and password and port.
It is built in .net core 2.0 - Problems are how can I add my username and password and port to this?
Your using the API not SMTP, Here is the standard smtp
var mailMessage = new MailMessage
{
From = new MailAddress("support#bla.net"),
Subject = "Hello World",
Body = "Test email from Send Grid SMTP Settings"
};
mailMessage.To.Add("someone#somehwere.net");
var smtpClient = new SmtpClient
{
Credentials = new NetworkCredential("Your-Username#azure.com", "Your-Password"),
Host = "smtp.sendgrid.net",
Port = 587
};
smtpClient.Send(mailMessage);

Complete ADFS login programmatically

I need to perform a complete AFDS login action in code. I cannot redirect the user to the ADFS login page. The user has already authenticated using a custom authentication mechanism and I use the same credentials to authenticate to ADFS, this to enable SSO to a SAP EP.
I can successfully retrieve a SAML token from the ADFS but SAP apparently can only handle the out of the box authentication. So I will need to authenticate the entire session.
This is what I have right now:
Retrieve the token:
var binding = new WS2007HttpBinding();
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = false;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
var trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress(AppSettings.AdfsUrl));
trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
trustChannelFactory.Credentials.UserName.UserName = user.UserName;
trustChannelFactory.Credentials.UserName.Password = PasswordService.Decrypt(user.UserPassword, user.UserID.ToString(CultureInfo.InvariantCulture));
trustChannelFactory.ConfigureChannelFactory();
// Create issuance issuance and get security token
var requestToken = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
requestToken.AppliesTo = new EndpointAddress(AppSettings.ServicePortalUrl);
requestToken.KeyType = WSTrust13Constants.KeyTypes.Bearer;
var tokenClient = (WSTrustChannel) trustChannelFactory.CreateChannel();
var token = tokenClient.Issue(requestToken) as GenericXmlSecurityToken;
return token;
And an attempt to get the claims so I could perhaps put the user principal in the HttpContext before redirecting to the SAP Portal. (Long shot)
var tokenHandlers = new SecurityTokenHandlerCollection(new SecurityTokenHandler[] { new SamlSecurityTokenHandler() });
tokenHandlers.First().Configuration.AudienceRestriction.AudienceMode = AudienceUriMode.Never;
tokenHandlers.First().Configuration.CertificateValidationMode = X509CertificateValidationMode.None;
tokenHandlers.Configuration.CertificateValidationMode = X509CertificateValidationMode.None;
var trusted = new TrustedIssuerNameRegistry("*.domain.com");
tokenHandlers.Configuration.IssuerNameRegistry = trusted;
var samlToken = tokenHandlers.ReadToken(new XmlTextReader(new StringReader(token.TokenXml.OuterXml)));
var claimsPrincipal = new ClaimsPrincipal(tokenHandlers.ValidateToken(samlToken).First());
HttpContext.Current.User = claimsPrincipal;
This does not work, as I keep on getting X509 certificate validation errors.
What I've tried:
Providing the SAML signature as MYSAPSSO2 token (long shot, did not work)
Putting the user principal in the HTTP context as I saw that SAP looks for an IPrincipal in the HTTP context. (Can't get it to work)
Set the MSISAuthenticated cookie, but have not idea how to get the value (base64 timestamp of moment of authentication?)
Is there any obvious way that I'm overseeing? Basically, I just want to perform the same authentication the ADFS login page does, but in code, so the user doesn't see a second login page.
Try it like this ...
// ######################### TOKEN HANDLER ########################################################################################################################
var genericToken = token as GenericXmlSecurityToken;
var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlerCollectionManager.SecurityTokenHandlerCollections.First();
// ######################## HANDLE AudienceRestriction programatically.############################################################################################
//handlers.Configuration.AudienceRestriction.AudienceMode.Equals(0);
handlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add(new Uri (svcEndpoint)); // porgramatically validate AllowedAudienceUris. This is your RP. https://learn.microsoft.com/en-us/dotnet/api/system.identitymodel.selectors.audienceurimode?view=netframework-4.8#fields
// ##### HANDLE STS SIGNING CERTIFICATE VALIDATIONS. Set to none for ADFS autocertificaterollover.
handlers.Configuration.CertificateValidationMode = X509CertificateValidationMode.None; //Also set in App.config / web.config
// ########################## HANDLE IssuerNameRegistry automatically.##############################################################################################
// ######################## READ METADATA OF ADFS TO EXTRACT SIGNING CERTIFICATE ###################################################################################
AdfsMetadataService svc = new AdfsMetadataLoader("https://" + opts.Farmname + "/FederationMetadata/2007-06/FederationMetadata.xml");
var metadata = svc.Get();
string IdP = metadata.Result.Identity;
string stringSigningCert = metadata.Result.SigningCertificateString;
// ####################### CONVERT FROM BASE64 TO READ SIGNING CERTIFICATE THUMBPRINT AND SUBJECT TO USE IN ISSUERNAMEREGISTRY #####################################
byte[] bytes = Convert.FromBase64String(stringSigningCert);
var AdfsSigncert = new X509Certificate2(bytes);
//Console.WriteLine(IdP + stringSigningCert + cert.Thumbprint + cert.Subject);
var registry = new ConfigurationBasedIssuerNameRegistry();
registry.AddTrustedIssuer(AdfsSigncert.Thumbprint, AdfsSigncert.Subject);
handlers.Configuration.IssuerNameRegistry = registry;
var cToken = handlers.ReadToken(new XmlTextReader(new StringReader(genericToken.TokenXml.OuterXml)));
var identity = handlers.ValidateToken(cToken).First();
var userIdenity = new ClaimsPrincipal(identity);
Console.WriteLine("Successfully Authenticated with identity type userIdenity.Identity.Name with value ~~~ " + userIdenity.Identity.Name);
foreach (var c in userIdenity.Claims)
{
Console.WriteLine("Claim Type = " + c.Type + " ~~~ Claim Value = " + c.Value);
}

httpclient postasync windows phone 8.1 universal app second call 404 error

I have a problem with httpclient in a universal windows phone 8.1 app.
I've been looking but i have not a valid solution in any post.
the problem is that, when i call to the web service first time runs correctly, but when i call it, second or third time, gives me an error 404.
Until you restart the application will not run again.
i need to send that data in a post function cause i want to send a xml formated to string.
my code is very simple:
var handler = new HttpClientHandler
{
Credentials = new
NetworkCredential("user", "pass", "domain")
};
using (var client = new HttpClient(handler))
{
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("XMLText", XMLText),
new KeyValuePair<string, string>("param1", "textParam1")
});
HttpResponseMessage response = new HttpResponseMessage();
response = await client.PostAsync(URL, formContent);
var responseString = response.Content.ReadAsStringAsync().Result;
MessageDialog msgbox = new MessageDialog(responseString);
await msgbox.ShowAsync();
}
and my web service is even simpler:
[WebMethod]
public String SetEnvioXML(string XMLText, string param1)
{
return XMLText;
}
Any solution?
Sorry for my english and thaks for all!
Any help is welcome!
Try to use the below code may be this will works,
First try to run this on Google Rest Client or Post Man
HttpRequestMessage httpRequest = new HttpRequestMessage();
httpRequest.Method = HttpMethod.Post;
httpRequest.RequestUri = URL;
httpRequest.Content = formContent ;
response =await client.SendAsync(httpRequest);
Finally i found the solution, i changed the autentication from windows autentication, to basic autentication in IIS, setting the domain in it. Then i try that:
client = new HttpClient();
var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}:{1}", "usuario", "contraseƱa"))));
client.DefaultRequestHeaders.Authorization = authHeader;
And it rules. Thanks for all of your answers!

Creating Google Drive DriveService with existing access token

I am using ASP.NET Web API and Google.Apis.Drive.v2 Client Library for .NET to upload files to users Drive.
All examples of using the Drive Client Library for .NET require a authentication flow. But how should I create the DriveService when I already know the access token?
Despite the fact that have been 2 years since the question has been asked, today I've encountered the same situation and my solution is:
var valid_token = "Pass_the_valid_token_here";
var token = new Google.Apis.Auth.OAuth2.Responses.TokenResponse()
{
AccessToken = valid_token,
ExpiresInSeconds = 3600,
Issued = DateTime.Now
};
var fakeflow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "fakeClientId",
ClientSecret = "fakeClientSecret"
}
});
UserCredential credential = new UserCredential(fakeflow, "fakeUserId", token);
var serviceInitializer = new BaseClientService.Initializer()
{
//ApplicationName = "Storage Sample",
HttpClientInitializer = credential
};
DriveService service = new DriveService(serviceInitializer);
Update
You could create your own custom token but the issue with this is going to be that the client library will not be able to refresh your access without the refresh token.
var token = new Google.Apis.Auth.OAuth2.Responses.TokenResponse()
{
AccessToken = valid_token,
ExpiresInSeconds = 3600,
Issued = DateTime.Now
};
var authorization = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "lientId",
ClientSecret = "ClientSecret"
}
});
var credential = new UserCredential(authorization, "user", token);
The issue you are going to have with this is that the client library is not going to be able refersh the access token after it has expired since you are not supplying a refresh token its only going to work for an hour.
The answer from Svetoslav Georgiev has so far worked well for me - Can't thank you enough. Google really don't help themselves with the lack of .Net (Asp Core) samples etc. Anway, one problem I did run into was that of referer restriction, so a addition/slight modification to the answer - Once you have the "service" and want to say upload a file, you need to set the referer on a buried HttpClient property...
FilesResource.CreateMediaUpload uploadRequest;
byte[] byteArray = Encoding.UTF8.GetBytes(html);
using (var stream = new MemoryStream(byteArray))
{
uploadRequest = service.Files.Create(fileMetadata, stream, "text/html");
uploadRequest.Service.HttpClient.DefaultRequestHeaders.Referrer = new Uri($"{baseUrl}");
uploadRequest.Fields = "id";
var progress = uploadRequest.Upload();
if (progress.Exception != null)
{
throw progress.Exception;
}
var file = uploadRequest.ResponseBody;
.... do what you will with file ....
}

Resources