Page_Load is not processing after async method obtains the required value - asynchronous

I have a page load that I am having difficulty with getting it to obtain a value from an async button click. The code is below. I am very new to this so please take that into consideration. What happens is essentially the code seems to just stop after the button is clicked and the GetAuthorizationCode executes. I get the value back on the temp Response in getReportButton_Click, but no other methods are executed on the Page_Load section. Essentially, I had this working in an older version of the Microsoft.Identity reference, but after upgrading it required switching many components to async and that is where I am stuck now.
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Params.Get("code") != null)
{
Session["AccessToken"] = GetAccessToken();
Response.Redirect("/Default.aspx");
}
if (Session["AccessToken"] != null)
{
accessToken.Value = Session["AccessToken"].ToString();
GetReport(0);
}
}
protected async void getReportButton_Click(object sender, EventArgs e)
{
var temp = await GetAuthorizationCode();
Response.Write(temp);
}
public async Task<string> GetAuthorizationCode()
{
var serviceUri = "XXXXXXXX";
var clientID = "XXXXXXXXX";
var userName = $"XXXXXXXX";
var password = "XXXXXXXXX";
using (var webClient = new WebClient())
{
var requestParameters = new NameValueCollection();
requestParameters.Add("resource", serviceUri);
requestParameters.Add("client_id", clientID);
requestParameters.Add("grant_type", "password");
requestParameters.Add("username", userName);
requestParameters.Add("password", password);
requestParameters.Add("scope", "openid");
var url = $"XXXXXXXXXXXX";
var responsebytes = await webClient.UploadValuesTaskAsync(url, "POST", requestParameters);
var responsebody = Encoding.UTF8.GetString(responsebytes);
return responsebody;
}
}

I ended up changing multiple aspects of this code to the point the original post isn't close to the ending code. Log story short, I pulled the GetAuthorizationCode() under the button click and moved it to the page_load, storing the output to a global variable. I then pass that global variable to the button click action to call the other async tasks.

Related

Pass values to a button from function

I have a function which is receiving parameters from another function and I have to pass these parameters to a button when it's execution get's complete !
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
// Next_Clicked(CompanyGp,CompanyId)
}
private void Next_Clicked(object sender, EventArgs e)
{
}
I have to pass these 2 parameters to that button !
you need to create class level variables to store these values
string _CompanyGp;
string _CompanyId;
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
// store the parameters in the class level variables
_CompanyGp = CompanyGp;
_CompanyId = CompanyId;
}
private void Next_Clicked(object sender, EventArgs e)
{
// you can now just reference _CompanyGp and _CompanyId
}
FYI, this is basic C# and really has nothing specific to do with Xamarin
Welcome to SO!
If CallCompanyApi and Next_Clicked located in different class, you can store them in Xamarin Forms by using Preferences.
using Xamarin.Essentials;
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
//Next_Clicked(CompanyGp,CompanyId)
Preferences.Set("CompanyGp", CompanyGp);
Preferences.Set("CompanyId", CompanyId);
}
Then in another class, click button will get them:
private void Next_Clicked(object sender, EventArgs e)
{
var CompanyGp = Preferences.Get("CompanyGp", "default_value");
var CompanyId = Preferences.Get("CompanyId", "default_value");
}
Else if they are in the same class, you can use the way as Jason's said.
============================Update=========================
You can set a default value if needed, such as follow:
var CompanyGp = Preferences.Get("CompanyGp", "Company_A");
var CompanyId = Preferences.Get("CompanyId", "1");
Defalut CompanyGp is Company_A, and default CompanyId is 1.

Passing parameters to remote SSRS report from ASP.NET MVC application

I have an ASP.NET MVC application that uses SSRS for reporting (using a web form and report viewer). I would like to pass two parameters dynamically to the remote report. My current implementation stores the parameters in session, which works fine on VS Development Server, but the variable is null on IIS, upon retrieval in the web form.
Here is the controller method that calls the view
public ActionResult ShowReport(string id)
{
var reportParameters = new Dictionary<string, string>();
reportParameters.Add("Param1", id);
reportParameters.Add("Param2", "user1");
Session["reportParameters"] = reportParameters;
return View("ReportName");
}
And here is how I attempt to retrieve the parameters from the web form
protected void Page_Load(object sender, EventArgs e)
{
var reportParameters = (Dictionary<string, string>)Session["reportParameters"];
foreach (var item in reportParameters)
{
ReportParameter rp = new ReportParameter(item.Key, item.Value);
ReportViewer1.ServerReport.SetParameters(rp);
}
}
Anyone know why Session["reportParameters"] is null?
Or is there some other way of passing these parameters?
You can do it too:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
try
{
var js = new JavaScriptSerializer();
string reportPath= Request.QueryString["LocalReport"];
string parametersTemp = Request.QueryString["ParametersReport"];
List<ReportParameter> parameters = null;
if (parametrosTemp != "")
{
parameters = JsonConvert.DeserializeObject
<List<ReportParameter>>(parametrosTemp);
}
GenerateReport(reportPath, parameters );
}
catch (Exception ex) {
statusReport.Value = ex.Message;
}
}
}
private void GenerateReport(string reportPath, List<ReportParameter> reportParameters)
{
reportCurrent.ProcessingMode = ProcessingMode.Remote;
ServerReport serverReport = reportCurrent.ServerReport;
serverReport.ReportServerUrl =
new Uri(AppSettings.URLReportServer);
serverReport.ReportPath = reportPath;
serverReport.Refresh();
if (reportParameters != null)
{
reportCurrent.ServerReport.SetParameters(reportParameters);
}
}
Is the problem that Session["reportParameters"] is null or is it that you don't get any parameters added to your report? Because your code, as it stands, won't add parameters to your report even if you pass them across properly and so the report parameters will be null.
SetParameters takes IEnumerable<ReportParameter> (usually a List), not a ReportParameterobject. Your code should look more like this:
protected void Page_Load(object sender, EventArgs e)
{
var reportParameters = (Dictionary<string, string>)Session["reportParameters"];
List<ReportParameter> parameters = new List<ReportParameter>();
foreach (var item in reportParameters)
{
parameters.Add(new ReportParameter(item.Key, item.Value););
}
ReportViewer1.ServerReport.SetParameters(parameters);
}

asp.net textbox not updated from another task

I have a GridView and on its SelectedIndexChanged the code is fired:
protected void grdEntry_SelectedIndexChanged(object sender, EventArgs e)
{
lblAssignId.Text = grdEntry.SelectedRow.Cells[1].Text == " "
? ""
: grdEntry.SelectedRow.Cells[1].Text;
Ob.BranchId = Globals.BranchID;
Ob.AssignId = lblAssignId.Text;
DataSet dsMain = GetAssignDetails(Ob);
if (dsMain.Tables[0].Rows.Count != 0)
{
// some other code
Task.Factory.StartNew(() => FillMemberShipAndBarCode(dsMain.Tables[0].Rows[0]["CustomerCode"].ToString(), Ob.BranchId));
}
}
and the code for filling membership id is
private void FillMemberShipAndBarCode(string customerCode, string branchId)
{
var sqlCommand = new SqlCommand
{
CommandText = "sp_customermaster",
CommandType = CommandType.StoredProcedure
};
sqlCommand.Parameters.AddWithValue("#CustomerCode", customerCode);
sqlCommand.Parameters.AddWithValue("#BranchId", branchId);
sqlCommand.Parameters.AddWithValue("#Flag", 18);
var data = PrjClass.GetData(sqlCommand);
txtMemberShip.Text = data.Tables[0].Rows[0]["MembershipId"].ToString();
txtBarCode.Text = data.Tables[0].Rows[0]["Barcode"].ToString();
}
It's working fine, but is is not updating any of the textboxes. Also, I checked in watch window, the values are returned as expected (M-1213 and 634-98-4 ) and the code does reaches the point txtMemberShip.Text = data.Tables[0].Rows[0]["MembershipId"].ToString();
but the txtMemberShip just remains empty??? Can anyone tell me why is not updating the textboxes?
UPDATE
As per comments, here is the page load
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindDropDown();
BindGrid();
SetDefaultsInTextBoxes();
}
}
And I don't have any code that waits on this task.
Don't do this:
Task.Factory.StartNew(() => FillMemberShipAndBarCode(dsMain.Tables[0].Rows[0]["CustomerCode"].ToString(), Ob.BranchId));
What are you trying to achieve by doing so?
What is probably happening is your method FillMemberShipAndBarCode is probably running after ASP.NET has already sent the page back to the browser. Thus, essentially, no visible effect on the rendered HTML.
ASP.NET isn't a good place to do multi-threaded stuff.
Try just replacing the above with this:
FillMemberShipAndBarCode(dsMain.Tables[0].Rows[0]["CustomerCode"].ToString(), Ob.BranchId);

How to resend email using SendAsync() in asp.net

I am using SendAsync to send an email. The reason I'm using async is simply to free up the UI rather than send multiple emails.
I have created the following callback event:
static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
var client = sender as SmtpClient;
var message = e.UserState as MailMessage;
if (e.Error.IsNotNull())
{
if (e.Error is SmtpFailedRecipientException)
{
var status = ((SmtpFailedRecipientException)(e.Error)).StatusCode;
if (status == SmtpStatusCode.MailboxBusy ||
status == SmtpStatusCode.MailboxUnavailable ||
status == SmtpStatusCode.TransactionFailed)
{
// a new message!
}
else
{
// TODO: Log other uncaught recipient failures
}
}
else
{
// TODO: Log all other failure reasons
}
}
client.Dispose();
message.Dispose();
}
As you can see I'm attempting to catch some recipients failures. If I find such an exception I want to try and resend the email.
I'm trying to work out how to resend the email safely. I'm thinking to create a new SmtpClient rather than reuse the existing one, but to be honest, I'm fairly new to .net and I'm not so sure of the implications.
Any advice would be appreciated.
Sending email asynchronously without delaying response back to the client(UI) requires a Backgroundworker in .Net. I implemented this on my site and will share the class source code with you.
using System;
using System.Collections.Generic;
using System.Web;
using System.ComponentModel; //Background worker namespace
using System.Net.Mail;
/// <summary>
/// Summary description for ClassName
/// </summary>
///
public class postmail
{
BackgroundWorker bw = new BackgroundWorker();
string email1, subject1, message1, failedemails;
public postmail(string email, string subject, string message)
{
bw.WorkerReportsProgress = false;
bw.WorkerSupportsCancellation = false;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
email1 = email;
subject1 = subject;
message1 = message;
}
public postmail()
{
// TODO: Complete member initialization
}
public void startsending() {
bw.RunWorkerAsync();
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.Flush(); // send all buffered output to client
HttpContext.Current.Response.End();
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
var finalemail = email1.Split(new[] { ',' }, StringSplitOptions.None);
//loop through the email addresses and send individually
for (int c = 0; c < finalemail.Length; c++) {
try
{
MailMessage mailMessage = new MailMessage();
// Sender Address
mailMessage.From = new MailAddress("emailaddress");
// Recepient Address
mailMessage.To.Add(finalemail[c].ToString());
// Subject
mailMessage.Subject = subject1.ToString();
// Body
mailMessage.Body = message1.ToString();
// format of mail message
mailMessage.IsBodyHtml = true;
// new instance of Smtpclient
SmtpClient mailSmtpClient = new SmtpClient("mail server");
//mailSmtpClient.EnableSsl = true;
mailSmtpClient.Credentials = new System.Net.NetworkCredential("emailaddress", "password");
// mail sent
Object userState = mailMessage;
mailSmtpClient.SendAsync(mailMessage, userState);
}
catch (Exception exc)
{
//fix for you
var ext = exc.ToString(); //catch exception for failed message
failedemails = failedemails + finalemail[c] + ","; //create a string of failed emails
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//called when the background process is done working
if(failedemails != null){
postmail(failedemails, subject1, message1); //resend the failed email
startsending();
}
}
}
Your concept might not be exact like mine but the key methods are:
Create an event handlers for the BackgroundWorker.
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = false;
bw.WorkerSupportsCancellation = false;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//Send your mail
}
catch (Exception exc)
{
//Catch exception here and call the resend method
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//do something after completion
}
The fix i made for you was to build a string of all failed addresses, then resend them after the backgroundworker is done working. cheers!!

IsAuthenticated is false! weird behaviour + review question

This is the login function (after I validate user name and password, I load user data into "user" variable and call Login function:
public static void Login(IUser user)
{
HttpResponse Response = HttpContext.Current.Response;
HttpRequest Request = HttpContext.Current.Request;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
user.UserId.ToString(), DateTime.Now, DateTime.Now.AddHours(12), false,
UserResolver.Serialize(user));
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(ticket));
cookie.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(cookie);
string redirectUrl = user.HomePage;
Response.Redirect(redirectUrl, true);
}
UserResolver is the following class:
public class UserResolver
{
public static IUser Current
{
get
{
IUser user = null;
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
user = Desrialize(ticket.UserData);
}
return user;
}
}
public static string Serialize(IUser user)
{
StringBuilder data = new StringBuilder();
StringWriter w = new StringWriter(data);
string type = user.GetType().ToString();
//w.Write(type.Length);
w.WriteLine(user.GetType().ToString());
StringBuilder userData = new StringBuilder();
XmlSerializer serializer = new XmlSerializer(user.GetType());
serializer.Serialize(new StringWriter(userData), user);
w.Write(userData.ToString());
w.Close();
return data.ToString();
}
public static IUser Desrialize(string data)
{
StringReader r = new StringReader(data);
string typeStr = r.ReadLine();
Type type=Type.GetType(typeStr);
string userData = r.ReadToEnd();
XmlSerializer serializer = new XmlSerializer(type);
return (IUser)serializer.Deserialize(new StringReader(userData));
}
}
And the global.asax implements the following:
void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
IPrincipal p = HttpContext.Current.User;
if (p.Identity.IsAuthenticated)
{
IUser user = UserResolver.Current;
Role[] roles = user.GetUserRoles();
HttpContext.Current.User = Thread.CurrentPrincipal =
new GenericPrincipal(p.Identity, Role.ToString(roles));
}
}
First question:
Am I do it right?
Second question - weird thing!
The user variable I pass to Login has 4 members: UserName, Password, Name, Id.
When UserResolver.Current executed, I got the user instance.
I descided to change the user structure - I add an array of Warehouse object.
Since that time, when UserResolver.Current executed (after Login), HttpContext.Current.User.Identity.IsAuthenticated was false and I couldn't get the user data.
When I removed the Warehouse[] from user structure, it starts to be ok again and HttpContext.Current.User.Identity.IsAuthenticated become true after I Login.
What is the reason to this weird behaviour?
First, you don't need to do an HttpContext.Current from Global.asax. Global.asax derives from HttpApplication. So all you need to do is to get the Context property. This might help make that code a little cleaner.
//this is all you need in your global.asax
void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if(Context.User.Identity.IsAuthenticated)
{
var user = UserResolver.Current;
Context.User = Thread.CurrentPrincipal = new UserWrapperPrincipal(user, Context.User.Identity);
}
}
//this helper class separates the complexity
public class UserWrapperPrincipal: IPrincipal, IUser
{
private readonly IUser _user;
private readonly IIdentity _identity;
public UserWrapperPrincipal(IUser user, IIdentity identity)
{
_user = user;
_identity = identity;
}
private IList<string> RoleNames
{
get { return _user.GetUserRoles().Select(role => role.ToString()); }
}
public IIdentity Identity { get { return _identity; } }
public bool IsInRole(string role) { return RoleNames.Contains(role); }
}
Based on your error, it seems like the issue is that either your serializing function or your deserializing function corrupts the data. However, the problem area is probably not those functions. Either there is an issue in serializing the Warehouse object (serializing complex types can sometimes be tricky), or in the serialization of the actual array. Since you are using the default .NET XmlSerializer, There is a good article on customizing and controlling the way different objects are handled available at http://www.diranieh.com/NETSerialization/XMLSerialization.htm .
On another note, are you sure that this is the best way for you to store this data in your application? Storing a user-id and name makes sense. When you start storing serialized arrays of complex objects in your cookie, it might indicate you are not approaching the problem correctly to begin with.
I am guessing that your code is in a log on event somewhere and your building a custom forms auth.
You also need to then build the User object from the cookie on every page request
public class AuthHttpModule : IHttpModule {
public virtual void Init(HttpApplication app) {
app.AuthenticateRequest += new EventHandler(app_AuthenticateRequest);
}
private void app_AuthenticateRequest(object source, EventArgs e) {
HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie == null) {
HttpContext.Current.User = null;
} else {
cookie = HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName];
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(ticket), new string[0]);
}
bool result = HttpContext.Current.Request.IsAuthenticated;
}
}
EDIT
Try adding this to your global
void Application_AuthenticateRequest(Object sender, EventArgs e)
HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null) {
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(ticket), new string[0]);
}
}

Resources