I have a form in my website which posts json to the async handler which validates the data and return back the resonse OK or error and i will make the redirect on the client based on the response give by my handler.
But when the response is ok, i want to perform some tasks asynchronously. But the asynchronous calls are not working inside the .ashx code. it is always synchronous.
Could you please give me an advice on this.?
code:
public class ValidateHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
NameValueCollection nvcForm = context.Request.Form;
Dictionary<string, string> errorFieldsDict = new Dictionary<string, string>();
foreach (string nameValueKey in nvcForm.AllKeys)
{
regExpToTest = string.Empty;
switch (nameValueKey)
{
case "firstName":
//validate
break;
case "lastName":
//validate
break;
case "email":
//validate
break;
case "phoneNumber":
//validate
break;
case "phoneCountryCode":
//validate
break;
case "country":
//validate
break;
case "addressLine1":
//validate
break;
case "addressLine2":
//validate
break;
case "city":
//validate
break;
case "postalCode":
//validate
break;
default:
//validate
break;
}
if (!string.IsNullOrEmpty(regExpToTest) && !Regex.IsMatch(nvcForm[nameValueKey], regExpToTest) && !string.IsNullOrEmpty(nvcForm[nameValueKey]))
{
errorFieldsDict.Add(nameValueKey, "Please Enter Correct Value");
isSuccess = false;
}
}
//Do your business logic here and finally
if (isSuccess)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
try
{
Dictionary<string, object> formValues = GetDictionaryForJson(nvcForm);
string previoiusUrl = GetRequestedURL(context);
string partner = string.Empty;
if (System.Web.HttpContext.Current.Session["yourpartner"] != null)
partner = System.Web.HttpContext.Current.Session["yourpartner"].ToString();
else if (System.Web.HttpContext.Current.Request.QueryString["utm_source"] != null)
partner = System.Web.HttpContext.Current.Request.QueryString["utm_source"];
else
partner = "company";
formValues.Add("partnerCode", partner);
string brochureType = string.Empty;
if (!string.IsNullOrEmpty(nvcForm["addressLine1"]) || !string.IsNullOrEmpty(nvcForm["addressLine2"]))
brochureType = "FBRO";
else
brochureType = "EBRO";
//Create a row in database
Item programItem = Sitecore.Context.Database.Items.GetItem(programRootpath + nvcForm["selectYourProgram"]); ;
AsyncMailSender caller = new AsyncMailSender(SendEmail);
IAsyncResult result = caller.BeginInvoke(programItem, nvcForm["email"], null, null);
}
catch (Exception ex)
{
isSuccess = false;
Log.Error("Enquiry handler failure: " + ex.Message, ex);
response.response = "error";
response.message = ex.Message;
context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(response));
}
if (isSuccess)
{
response.response = "ok";
context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(response));
}
}
else
{
response.response = "errorFields";
response.errorFields = errorFieldsDict;
context.Response.ContentType = "application/json";
string responseJson = JsonConvert.SerializeObject(response);
context.Response.Write(JsonConvert.SerializeObject(response, Newtonsoft.Json.Formatting.None));
}
}
private string GetRequestedURL(HttpContext context)
{
string previousURL = string.Empty;
try
{
previousURL = context.Request.ServerVariables["HTTP_REFERER"];
}
catch
{
previousURL = context.Request.Url.AbsolutePath;
}
return previousURL;
}
public bool IsReusable
{
get
{
return false;
}
}
private void SendEmail(Item programItem, string toEmail)
{
if (programItem != null)
{
SendEmail()
}
}
private Dictionary<string, object> GetDictionaryForJson(NameValueCollection formValues)
{
Dictionary<string, object> formDictionary = new Dictionary<string, object>();
foreach (string key in formValues.AllKeys)
{
formDictionary.Add(key, formValues[key]);
}
return formDictionary;
}
}
public delegate void AsyncMailSender(Item program, string toAddress);
PS: I did hide some code which is just our business.But Would be great if you can comment on that.
thanks guys
In ASP.NET 4.5 is the HttpTaskAsyncHandler. You can use it like this:
public class MyHandler : HttpTaskAsyncHandler {
public override async Task ProcessRequestAsync(HttpContext context) {
await WhateverAsync(context);
}
}
You need to implmement IHttpAsyncHandler rather than IHttpHandler and register it as such in the web.config file. Browsers will also observe connection limits, so make sure IIS is configured properly to handle multiple connections, keep-alive, etc.
Here's a detailed walk through: http://msdn.microsoft.com/en-us/library/ms227433.aspx
Related
I have an android app which is making api requests to my server running Spring MVC. The RestController works fine when I make a request from the browser but it responds with 404 when I am making requests from android. Not sure why
Here is code snippet from Android app making requests
public class AsyncFetch extends AsyncTask<Pair<String, String>, String, String> {
public ProgressDialog pdLoading;
private HttpURLConnection conn;
private String urlStr;
private String requestMethod = "GET";
public AsyncFetch(String endpoint, Context ctx)
{
pdLoading = new ProgressDialog(ctx);
Properties reader = PropertiesReader.getInstance().getProperties(ctx, "app.properties");
String host = reader.getProperty("host", "10.0.2.2");
String port = reader.getProperty("port", "8080");
String protocol = reader.getProperty("protocol", "http");
String context = reader.getProperty("context", "");
this.urlStr = protocol+"://"+host+":"+port+context+endpoint;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method will be running on UI thread
pdLoading.setMessage("\tLoading...");
pdLoading.setCancelable(false);
pdLoading.show();
}
#Override
protected String doInBackground(Pair<String, String>... params) {
URL url;
try {
url = new URL(urlStr);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return e.toString();
}
try {
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
conn.setConnectTimeout(CONNECTION_TIMEOUT);
conn.setRequestMethod(requestMethod);
conn.setDoOutput(true);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return e1.toString();
}
try {
int response_code = conn.getResponseCode();
// Check if successful connection made`enter code here`
if (response_code == HttpURLConnection.HTTP_OK) {
// Read data sent from server
InputStream input = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
// Pass data to onPostExecute method
return (result.toString());
} else {
return ("unsuccessful");
}
} catch (IOException e) {
e.printStackTrace();
return e.toString();
} finally {
conn.disconnect();
}
}
Spring MVC Controller
#RestController
public class ApiController {
#RequestMapping(value = "homefeed", method=RequestMethod.GET)
public String homefeed(#RequestParam(value="userId", required = false) Integer id, #RequestParam(value="search", required = false) String search, #RequestParam(value="page", required = false, defaultValue = "0") Integer page) { ... }
}
localhost:8080/api/homefeed -- works
127.0.0.1:8080/api/homefeed -- works
My Public IP:8080/api/homefeed -- does not works
10.0.2.2:8080/api/homefeed -- android emulator to localhost -- does not work
10.0.2.2:8080/Some resource other than the api endpoint -- works
Any help is highly appreciable, have wasted quiet some time in debugging.
I'm adding confirmation email feature to my ASP.NET WebAPI project. The server can send email fine, however, the confirmation link always return "Invalid token".
I checked some reasons as pointed out here
http://tech.trailmax.info/2015/05/asp-net-identity-invalid-token-for-password-reset-or-email-confirmation/
but it seems that none of them is the root cause
Below is my code:
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
try
{
await userManager.AddToRoleAsync(user.Id, "Player");
//Generate email confirmation token
//var provider = new DpapiDataProtectionProvider("GSEP");
var provider = new MachineKeyProtectionProvider();
userManager.UserTokenProvider = new DataProtectorTokenProvider<GSEPUser>(provider.Create("EmailConfirmation"));
var code = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);
code = System.Web.HttpUtility.UrlEncode(code);
EmailHelper emailHelper = new EmailHelper();
string callBackUrl = emailHelper.GetCallBackUrl(user, code);
EmailMessage message = new EmailMessage();
message.Body = callBackUrl;
message.Destination = user.Email;
message.Subject = "GSEP Account confirmation";
emailHelper.sendMail(message);
}
catch (Exception e)
{
return Ok(GSEPWebAPI.App_Start.Constants.ErrorException(e));
}
}
And now is EmailHelper
public class EmailHelper
{
public string GetCallBackUrl(GSEPUser user, string code)
{
var newRouteValues = new RouteValueDictionary(new { userId = user.Id, code = code });
newRouteValues.Add("httproute", true);
UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext, RouteTable.Routes);
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
return callbackUrl;
}
public void sendMail(EmailMessage message)
{
#region formatter
string text = string.Format("Please click on this link to {0}: {1}", message.Subject, message.Body);
string html = "Please confirm your account by clicking this link: link<br/>";
html += HttpUtility.HtmlEncode(#"Or click on the copy the following link on the browser:" + message.Body);
#endregion
MailMessage msg = new MailMessage();
msg.From = new MailAddress("myemail#example.com");
msg.To.Add(new MailAddress(message.Destination));
msg.Subject = message.Subject;
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
SmtpClient smtpClient = new SmtpClient("smtp-mail.outlook.com", Convert.ToInt32(587));
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("myemail#example.com", "mypassword!");
smtpClient.Credentials = credentials;
smtpClient.EnableSsl = true;
smtpClient.Send(msg);
}
}
And 2 MachineKey class
public class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
public class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
return MachineKey.Protect(userData, _purposes);
}
public byte[] Unprotect(byte[] protectedData)
{
return MachineKey.Unprotect(protectedData, _purposes);
}
}
I also added machineKey tag in Web.config as some instruction pointed out.
And finally is my confirmation email API
[AllowAnonymous]
[HttpGet]
public async Task<IHttpActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return Ok("Confirm error");
}
IdentityResult result;
try
{
result = await UserManager.ConfirmEmailAsync(userId, code);
}
catch (InvalidOperationException ioe)
{
// ConfirmEmailAsync throws when the userId is not found.
return Ok("UserID not found");
}
if (result.Succeeded)
{
return Ok("Confirmation succesfully");
}
else
{
return Ok(result.Errors);
}
}
Please show me where am I go wrong
I know this is an old thread. But I though of adding the answer as it could help others.
You are using the below code
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
and the UrlHelper.Action already does the url encoding for you in the latest MVC versions. So here in your code you are doing the encoding twice (one inside the Register and another inside GetCallBackUrl using urlHelper.Action) and that is why you are getting the invalid token error.
I'm trying to get an auth basic on my web api. I've written a simple HttpModule to check it
public class BasicAuth : IHttpModule
{
SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["Connection"].ConnectionString);
private const string Realm = "MyRealm";
public void Init(HttpApplication context)
{
// Register event handlers
context.AuthorizeRequest += new EventHandler(OnApplicationAuthenticateRequest);
context.EndRequest += new EventHandler(OnApplicationEndRequest);
}
private static void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
private bool CheckPassword(string username, string password)
{
var parameters = new DynamicParameters();
parameters.Add("#UserName", username);
parameters.Add("#Password", password);
con.Open();
try
{
var query = //query to db to check username and password
return query.Count() == 1 ? true : false;
}
catch
{
return false;
}
finally
{
con.Close();
}
}
private bool AuthenticateUser(string credentials)
{
try
{
var encoding = Encoding.GetEncoding("iso-8859-1");
credentials = encoding.GetString(Convert.FromBase64String(credentials));
int separator = credentials.IndexOf(':');
string name = credentials.Substring(0, separator);
string password = credentials.Substring(separator + 1);
if (CheckPassword(name, password))
{
var identity = new GenericIdentity(name);
SetPrincipal(new GenericPrincipal(identity, null));
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
private void OnApplicationAuthenticateRequest(object sender, EventArgs e)
{
var authHeader = request.Headers["Authorization"];
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeaderVal.Scheme.Equals("basic",
StringComparison.OrdinalIgnoreCase) &&
authHeaderVal.Parameter != null)
{
if (AuthenticateUser(authHeaderVal.Parameter))
{
//user is authenticated
}
else
{
HttpContext.Current.Response.StatusCode = 401;
}
}
else
{
HttpContext.Current.Response.StatusCode = 401;
}
}
catch
{
HttpContext.Current.Response.StatusCode = 401;
}
}
private static void OnApplicationEndRequest(object sender, EventArgs e)
{
var response = HttpContext.Current.Response;
if (response.StatusCode == 401)
{
response.Headers.Add("WWW-Authenticate",
string.Format("Basic realm=\"{0}\"", Realm));
}
}
public void Dispose()
{
}
}
well, this code works pretty well, except the fact it asks for basic auth even on controller I don't put the [Authorize] tag on. And when it occurs, it gives the right data back.
Let me explain:
My HistoryController has [Authorize] attribute, to make a POST request I have to send Header auth to get data, if I don't do it, I receive 401 status code and a custom error.
My HomeController doesn't have [Authorize] attribute, if i make a get request on my homepage, the browser popups the authentication request, but if I hit Cancel it shows my home page. (The page is sent back with 401 error, checked with fiddler).
What am I doing wrong?
I have hosted a Windows Web API using a basic authentication header with username and password.
I'm trying to create a login form that takes a username and password and sends back a token.
so i have the following code.
I'm using a Attributed method
public class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
private IPromiseRepository promiseRepository;
public BasicAuthenticationAttribute()
{
this.promiseRepository = new EFPromiseRepository(new PropellorContext());
//repository = promiseRepository;
}
public BasicAuthenticationAttribute(IPromiseRepository promiseRepository, INewsFeedRepository newsfeedRepository)
{
this.promiseRepository = promiseRepository;
}
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization == null)
{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
else
{
string authToken = actionContext.Request.Headers.Authorization.Parameter;
string decodedToken = authToken;
// Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
string username = decodedToken.Substring(0, decodedToken.IndexOf(":"));
string password = decodedToken.Substring(decodedToken.IndexOf("^")+1);
string APIToken = decodedToken.Substring(decodedToken.IndexOf("="));
APIToken = APIToken.Replace("=", string.Empty);
password = password.Replace("=", string.Empty);
if (!string.IsNullOrEmpty(APIToken))
{
password = password.Replace(APIToken, string.Empty);
}
if (username != null && password != null)
{
try
{
var user = promiseRepository.GetUserByName(username);
var salt = user.PasswordSalt;
System.Security.Cryptography.SHA512Managed HashTool = new System.Security.Cryptography.SHA512Managed();
Byte[] PasswordAsByte = System.Text.Encoding.UTF8.GetBytes(string.Concat(password, salt));
Byte[] EncryptedBytes = HashTool.ComputeHash(PasswordAsByte);
HashTool.Clear();
var hashedpass = Convert.ToBase64String(EncryptedBytes);
if (hashedpass == user.Password)
{
if (string.IsNullOrEmpty(user.APIToken))
{
String guid = System.Guid.NewGuid().ToString();
user.APIToken = guid;
promiseRepository.UpdateUser(user);
promiseRepository.Save();
}
if (user != null)
{
user = promiseRepository.GetUserByUserID(user.UserID);
HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(user), new string[] { });
base.OnActionExecuting(actionContext);
}
}
if (APIToken != null)
{
if (user.APIToken == APIToken)
{
var userbytoken = promiseRepository.GetUserByAPIToken(APIToken);
HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(userbytoken), new string[] { });
base.OnActionExecuting(actionContext);
}
}
}
catch (Exception)
{
{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
base.OnActionExecuting(actionContext);
}
throw;
}
}
}
}
}
This works with Fiddler when the correct credentials are passed
I'm attempting to produce the same authentication in my windows phone application.
Passes a username and password into the basic authentication http header.
However I'm not sure how to do this after a large amount of diggging on the internet alot of the exmaples are windows phone 7 and certain methods don't exist anymore.
This is the code i have arrived at.
private void Login1_Click(object sender, RoutedEventArgs e)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:5650/api/start");
NetworkCredential credentials = new NetworkCredential(userName.Text + ":^",password.Text + "=");
request.Credentials = credentials;
request.BeginGetResponse(new AsyncCallback(GetSomeResponse), request);
Hopefully someone can guide me into the right direction.
it should be simple in principle :(
Here is a sample using HttpClient:
public static async Task<String> Login(string username, string password)
{
HttpClient Client = new HttpClient();
Client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(StringToAscii(string.Format("{0}:{1}", username, password))));
var response = await Client.GetAsync(new Uri(new Uri("http://yourdomain.com"), "/login"));
var status= await response.Content.ReadAsAsync<String>();
return status;
}
And of course you can find the ToBase64String function on the internet. The tricky part here is the Authorization header.
Iam using GoogleDriveAPI to upload Documents to Drive from Asp.net.It is working fine but i need to use ClientID and ClientSecret for Authentication. Not the gmail userName/Password.After Authentication for Authorization it is redirected to gmail for login after login it is asking for AccessPermission for Drive.So how can i pass the GmailUserID and Password for Authentication not the ClientID and ClientSecret . and after that can i restrict again from Login for Authorization .
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DotNetOpenAuth.OAuth2;
using Google.Apis.Authentication.OAuth2;
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth;
using Google.Apis.Drive.v2;
using Google.Apis.Drive.v2.Data;
using Google.Apis.Util;
using System.Diagnostics;
using DotNetOpenAuth.Messaging;
using System.Text;
using System.IO;
public partial class _Default : System.Web.UI.Page
{
private static DriveService driveService;
private static OAuth2Authenticator<WebServerClient> authenticator;
private static IAuthorizationState _state;
String CLIENT_ID = "90994017777728.apps.googleusercontent.com";
String CLIENT_SECRET = "IR777777773Nf3vnLT0v";
private static readonly string[] SCOPES = new[] { DriveService.Scopes.Drive.GetStringValue() };
protected void Page_Load(object sender, EventArgs e)
{
Login();
}
private IAuthorizationState AuthState {
get {
return _state ?? HttpContext.Current.Session["GoogleAuthState"] as IAuthorizationState;
}
}
private OAuth2Authenticator<WebServerClient> CreateAuthenticator() {
var provider = new WebServerClient(GoogleAuthenticationServer.Description,CLIENT_ID,CLIENT_SECRET);
var authenticator = new OAuth2Authenticator<WebServerClient>(provider,GetAuthorization);
return authenticator;
}
private IAuthorizationState GetAuthorization(WebServerClient client) {
IAuthorizationState state = AuthState;
if (state != null) {
if (state.AccessTokenExpirationUtc.Value.CompareTo(DateTime.Now.ToUniversalTime()) > 0)
return state;
else
state = null;
}
state = client.ProcessUserAuthorization(new HttpRequestInfo(HttpContext.Current.Request));
if (state != null && (!string.IsNullOrEmpty(state.AccessToken) || !string.IsNullOrEmpty(state.RefreshToken))) {
if (state.RefreshToken == null)
state.RefreshToken = "";
HttpContext.Current.Session["GoogleAuthState"] = _state = state;
return state;
}
client.RequestUserAuthorization(SCOPES,"",HttpContext.Current.Request.Url); // Redirecting to Gmail LoginPage
return null;
}
private string GetContentType(string fileExtension) {
if (string.IsNullOrEmpty(fileExtension))
return string.Empty;
string contentType = string.Empty;
switch (fileExtension) {
case "htm":
case "html":
contentType = "text/HTML";
break;
case "txt":
contentType = "text/plain";
break;
case "doc":
case "rtf":
case "docx":
contentType = "Application/msword";
break;
case "xls":
case "xlsx":
contentType = "Application/x-msexcel";
break;
case "jpg":
case "jpeg":
contentType = "image/jpeg";
break;
case "png":
contentType = "image/png";
break;
case "bmp":
contentType = "image/bmp";
break;
case "gif":
contentType = "image/GIF";
break;
case "pdf":
contentType = "application/pdf";
break;
}
return contentType;
}
public void Login() {
if (authenticator == null)
authenticator = CreateAuthenticator();
if (driveService == null) {
driveService = new DriveService(authenticator);
}
}
protected void Button1_Click(object sender,EventArgs e) {
string[] stringParts = FileUpload1.FileName.Split(new char[] { '/' });
string str = stringParts[stringParts.Length - 1].ToString();
string[] strType = str.Split(new char[] { '.' });
string type = GetContentType(strType[1]);
Google.Apis.Drive.v2.Data.File newFile = new Google.Apis.Drive.v2.Data.File { Title = FileUpload1.FileName,MimeType = type };
byte[] byteArray = FileUpload1.FileBytes;
MemoryStream stream = new MemoryStream(byteArray);
FilesResource.InsertMediaUpload request = driveService.Files.Insert(newFile,stream,newFile.MimeType);
request.Convert = true;
request.Upload();
Google.Apis.Drive.v2.Data.File file = request.ResponseBody;
InsertPermission(driveService,file);
HttpContext.Current.Session["GoogleAuthState"] = null;
Response.Write(file.AlternateLink);
}
public void InsertPermission(DriveService service,Google.Apis.Drive.v2.Data.File file) {
Permission newPermission = new Permission();
newPermission.Value = TextBox1.Text;
newPermission.Type = "user";
newPermission.Role = "reader";
try {
Permission per = service.Permissions.Insert(newPermission,file.Id).Fetch();
}
catch (Exception e) {
Console.WriteLine("An error occurred: " + e.Message);
}
}