I'm trying to use new linq2twitter version (4.1.0) but i just can't get it work.
I used to work with version 2.1.11 until now and it worked just fine.
i've opened a new asp.net project and this is my code
Can you tell me what i am doing wrong?
The "DoSingleUserAuth" works fine. i enter the right tokens...
protected void Page_Load(object sender, EventArgs e)
{
Task demoTask = DoDemosAsync();
demoTask.Wait();
}
static async Task DoDemosAsync()
{
var auth = DoSingleUserAuth();
var twitterCtx = new TwitterContext(auth);
await ShowFriendsAsync(twitterCtx);
}
static IAuthorizer DoSingleUserAuth()
{
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = "ConsumerKey",
ConsumerSecret = "ConsumerSecret",
AccessToken = "AccessToken",
AccessTokenSecret = "AccessTokenSecret"
}
};
return auth;
}
static async Task ShowFriendsAsync(TwitterContext twitterCtx)
{
var friendship =
await
(from friend in twitterCtx.Friendship
where friend.Type == FriendshipType.Show &&
friend.SourceScreenName == "Linq2Twitr" &&
friend.TargetScreenName == "JoeMayo"
select friend)
.SingleOrDefaultAsync();
if (friendship != null &&
friendship.SourceRelationship != null &&
friendship.TargetRelationship != null)
{
Console.WriteLine(
"\nJoeMayo follows LinqToTweeter: " +
friendship.SourceRelationship.FollowedBy +
"\nLinqToTweeter follows JoeMayo: " +
friendship.TargetRelationship.FollowedBy);
}
}
10x,
Lior
There are two things you can do to fix this, make your page async and replace Wait with await:
Add the Async="true" attribute to your #Page directive:
<%# Page Async="true" ... %>
You can rewrite Page_Load by making it async and awaiting DoDemosAsync like this:
protected async void Page_Load(object sender, EventArgs e)
{
await DoDemosAsync();
}
The problem was that calling Wait() caused a deadlock. With async, you should make your calls async all the way through the call chain.
i can see that
var result = Task.Run(() => ShowFriendsAsync(twitterCtx)).Result;
works fine for me. is this a good approach?
Lior
Related
In asp.net core 6 and CSOM library, I'm trying add a permission to a SPO file as following code.
public async Task<IActionResult> AddPermission(Guid guid, String[] emailList)
{
using (var authenticationManager = new AuthenticationManager())
using (var context = authenticationManager.GetContext(_site, _user, _securePwd))
{
File file= context.Web.GetFileById(guid);
SetFilePermission(context, file, emailList);
file.ListItemAllFields.SystemUpdate();
context.Load(file.ListItemAllFields);
await context.ExecuteQueryAsync();
return NoContent();
}
}
private static void SetFilePermission(ClientContext context, File file, string[] emailList)
{
if (emailList != null)
{
file.ListItemAllFields.BreakRoleInheritance(true, false);
var role = new RoleDefinitionBindingCollection(context);
role.Add(context.Web.RoleDefinitions.GetByType(permissionLevel));
foreach (string email in emailList)
{
User user = context.Web.SiteUsers.GetByEmail(email);
file.ListItemAllFields.RoleAssignments.Add(user, role);
}
}
}
This work successfully if only the user is available in SPO, or exception occurs. To avoid non-available user exception, I tried to move Load() and ExecuteQuery() to SetFilePermission method.
public async Task<IActionResult> AddPermission(Guid guid, String[] emailList)
{
using (var authenticationManager = new AuthenticationManager())
using (var context = authenticationManager.GetContext(_site, _user, _securePwd))
{
File file= context.Web.GetFileById(guid);
SetFilePermission(context, file, emailList);
// file.ListItemAllFields.SystemUpdate();
// context.Load(file.ListItemAllFields);
// await context.ExecuteQueryAsync();
return NoContent();
}
}
private static void SetFilePermission(ClientContext context, File file, string[] emailList)
{
if (emailList != null)
{
file.ListItemAllFields.BreakRoleInheritance(true, false);
var role = new RoleDefinitionBindingCollection(context);
role.Add(context.Web.RoleDefinitions.GetByType(permissionLevel));
foreach (string email in emailList)
{
User user = context.Web.SiteUsers.GetByEmail(email);
file.ListItemAllFields.RoleAssignments.Add(user, role);
// Move load and executequery method to here.
file.ListItemAllFields.SystemUpdate();
context.Load(file.ListItemAllFields);
context.ExecuteQueryAsync();
}
}
}
Suddenly, exception disappear even though the user is not available in SPO!
But other available emails in emailList also fail to add permission, just result in return NoContent eventually. Does anyone know the myth behind the process and explain it to me?
public async Task<ObservableCollection<CustomerModel>> GetCustomer(string customerNumber, string department)
{
try
{
progressBar.Visibility = ViewStates.Visible;
progressBar.Progress = 0;
listofItems = new ObservableCollection<CustomerModel>();
string url = _client.BaseAddress + "/getcustomers(Number='" + customerNumber + "',department='" +
department + "')";
var response = await _client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
progressBar.Visibility = ViewStates.Invisible;
progressBar.Progress = 100;
string returnjson = await response.Content.ReadAsStringAsync();
ReplyCustomerModel replyCustomerModel =
JsonConvert.DeserializeObject<ReplyCustomerModel>(returnjson);
if (replyCustomerModel != null)
{
listofItems = replyCustomerModel.Customers;
}
}
else
{
AlertDialog.Builder alertDiag = new AlertDialog.Builder();
alertDiag.SetTitle("Butikscanner App");
alertDiag.SetMessage("User Does not exist");
alertDiag.SetPositiveButton("OK",
(senderAlert, args) => { });
alertDiag.SetNegativeButton("Cancel", (senderAlert, args) => { alertDiag.Dispose(); });
Dialog diag = alertDiag.Create();
diag.Show();
}
return listofItems;
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
Actually that is what i am doing if my response is false i am trying to show alert dialog that user does not exist I am working my project in MVVM light
Actually that is what i am doing if my response is false i am trying to show alert dialog that user does not exist I am working my project in MVVM light
Actually that is what i am doing if my response is false i am trying to show alert dialog that user does not exist I am working my project in MVVM light
Usually, API calls are made in a background thread using async-await if that is the case with you as well then I would suggest that you do is call the dialog's show method on the UIThread. For this, you will need an activity context i.e. An activity's reference.
There are two way for you to do it either directly call this method as an action something like this:
private void ShowDialog()
{
AlertDialog.Builder alertDiag = new AlertDialog.Builder();
alertDiag.SetTitle("Butikscanner App");
alertDiag.SetMessage("User Does not exist");
alertDiag.SetPositiveButton("OK",(senderAlert, args) => { });
alertDiag.SetNegativeButton("Cancel", (senderAlert, args) => { alertDiag.Dispose(); });
Dialog diag = alertDiag.Create();
diag.Show();
}
assuming above is how your method is defined you can run it on UI thread like:
activity.RunOnUIThread(ShowDialog);
But in your scenario, I do not personally think that this is a smart thing to do because the only line of code that is supposed to be on UIThread(at least i think so) is the dialog.Show();
What you should do rather would be use a lamba expression for a anonymous method something like:
private void ShowDialog(Activity activity)
{
AlertDialog.Builder alertDiag = new AlertDialog.Builder();
alertDiag.SetTitle("Butikscanner App");
alertDiag.SetMessage("User Does not exist");
alertDiag.SetPositiveButton("OK",(senderAlert, args) => { });
alertDiag.SetNegativeButton("Cancel", (senderAlert, args) => { alertDiag.Dispose(); });
Dialog diag = alertDiag.Create();
activity.RunOnUIThread(()=>
{diag.Show();});
}
I have a web application utilizing master pages. For some reason, when I add a buttonclick event, the method is never hit. The page goes through the normal page_load events. How do I get my button click event to fire? Previously, This worked just fine, now this is happening in my whole application where the !page.IsPostBack always evaluates false from a button_Click
I have tried adding script Handlers and that doesnt seem to help
in the UI page:
<asp:Button ID="Button1" CssClass="btn btn-primary"
OnClick="putAccoutDetail" runat="server" Text="Save Changes" />
in the CodeBehind
protected void Page_Load(object sender, EventArgs e)
{
if (Session["Authenticated"] == null ||
Session["Authenticated"].ToString() != "true")
{
Response.Redirect("~/Login.aspx");
}
if (!Page.IsPostBack)
{
if (Session["UserID"] != null)
{
UserID = Convert.ToInt32(Session["UserID"]);
getUserData(UserID);
}
}
}
public void putAccoutDetail(object sender, EventArgs e)
{
string statusMsg = string.Empty;
var userInfo = db.UserMasts.FirstOrDefault(s => s.ID == UserID);
if (userInfo != null)
{
userInfo.UserName = txtUserName.Text;
userInfo.MilEmail = txtEmail.Text;
string base64 = Request.Form["imgCropped"];
if (base64.Length > 0)
{
byte[] bytes = Convert.FromBase64String(base64.Split(',')[1]);
String fileName = Guid.NewGuid().ToString() + ".png";
userInfo.PhotoPath = fileName;
ImagePhoto.ImageUrl = "/Images/Users/" + userInfo.PhotoPath;
using (FileStream stream = new FileStream(Server.MapPath("~/Images/Users/" + fileName), FileMode.Create))
{
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
}
}
try
{
dHelper.LogAction("Update User Detail : " + userInfo.UserName);
db.SubmitChanges();
statusMsg = "Successfully Updated";
lblstatusMsg.Text = statusMsg;
lblstatusMsg.Visible = true;
}
catch(Exception ex)
{
statusMsg = "Update Failed";
lblstatusMsg.Text = statusMsg;
lblstatusMsg.Visible = true;
}
}
The issue was that the form had unhandled ASP validators on certain fields. I added a validation group to those and then handled them in the button_Click and all is working
It was working good, but I made some changes in the api, adding more controllers nothing out of the place, and then it stops working, always thrown an exception: "TaskCanceledException: A task was canceled" in the line GetAsync().result. I increase the timeout and infinitely stays loading.
The code controller APP who make a request to the controller API:
public ActionResult Login(LoginM us)
{
try
{
cuentaM account = new cuentaM();
HttpClient client = new HttpClient();
var result = client.GetAsync("http://localhost:26723/api/Login" + "?email=" + us.email + "&password=" + us.password).Result;
if (result.IsSuccessStatusCode)
{
account = result.Content.ReadAsAsync<cuentaM>().Result;
}
Session["cuenta"] = account;
return RedirectToAction("Index", "Home");
}
catch (Exception ex)
{
throw;
}
}
The controller API code:
public HttpResponseMessage Get(string email, string password)
{
try
{
using (elevationbEntities db = new elevationbEntities())
{
usuario user = db.usuarios.Where(m => m.email == email && m.password == password).SingleOrDefault();
cuentaM account = new cuentaM();
if (user != null)
{
account = (from o in db.cuentas
join cu in db.cuentausuarios on o.idCuenta equals cu.idCuenta
join u in db.usuarios on cu.idUsuario equals u.idUsuario
where u.idUsuario == user.idUsuario
select new cuentaM { idUsuario = user.idUsuario, idCuenta = o.idCuenta, CodigoUnico = o.CodigoUnico })
.FirstOrDefault();
}
else
{
account.Error = "Wrong Password or Email";
}
HttpResponseMessage response;
response = Request.CreateResponse(HttpStatusCode.OK, account);
return response;
}
}
catch (TaskCanceledException ex)
{
HttpResponseMessage response;
response = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
return response;
}
}
Making blocking calls (.Result) on HttpClinet's async API can cause deadlocks especially if being used asp.net MVC, which may have async operations being invoked when the blocking call was made.
Make the code async all the way through.
Also try to avoid creating an instance of HttpClient on every request. This can cause sockets to be exhausted.
private static HttpClient client = new HttpClient();
public async Task<ActionResult> Login(LoginM us) {
try {
cuentaM account = new cuentaM();
var url = "http://localhost:26723/api/Login" + "?email=" + us.email + "&password=" + us.password
var result = await client.GetAsync(url);
if (result.IsSuccessStatusCode) {
account = await result.Content.ReadAsAsync<cuentaM>();
}
Session["cuenta"] = account;
return RedirectToAction("Index", "Home");
} catch (Exception ex) {
throw;
}
}
You may be deadlocking by blocking on an async call, as described in this article. Here's the problematic line:
account = result.Content.ReadAsAsync<cuentaM>().Result;
Change the method signature for Login to:
public async Task<ActionResult> Login(LoginM us)
Then change the problematic line to use await instead of .Result:
account = await result.Content.ReadAsAsync<cuentaM>();
I have a MVC app where I have a User class and the user can also impersonate another user(Admin users only).
So I have this code below that authenticates the request and instantiates my version of a User class.
It then tries to get the impersonated user from the Session object but Session is not available in this method in the global.asax.
Hope this makes sense.
How else could I do this?
My question I guess is at what point in the global.asax methods do you get access to Session object for each request?
protected void Application_OnAuthenticateRequest(object sender, EventArgs e)
{
IMylesterService service = ObjectFactory.GetInstance<IMylesterService>();
if (Context.User != null)
{
if (Context.User.Identity.IsAuthenticated)
{
User user = service.GetUser(Context.User.Identity.Name);
if (user == null)
throw new ApplicationException("Context.user.Identity.name is not a recognized user");
User impersonatedUser = (User)this.Session["ImpersonatedUser"];
if (impersonatedUser == null)
user.ImpersonatedUser = user;
else
user.ImpersonatedUser = impersonatedUser;
System.Threading.Thread.CurrentPrincipal = Context.User = user;
return;
}
}
User guest = service.GetGuestUser();
guest.ImpersonatedUser = guest;
System.Threading.Thread.CurrentPrincipal = Context.User = guest;
}
Try creating an authorization filter:
public class CustomAuthorizationFilter : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
// perform your authorization here
// full access to HttpContext and session
}
}
You can then apply this attribute to your controllers. Ideally you'd have a base controller that all other controllers inherit from and you could apply the attribute at the class level on that controller. Then all of your requests would be authorized and apply the impersonation as you have coded above.
Session will not be available during AuthenticateRequest: What you will need to do is tag the required information to the Identity.userData; so for example if you where using forms authentication do the following:
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.User != null)
{
if (Context.User.Identity.IsAuthenticated)
{
// retrieve the value
var id = (FormsIdentity)Context.User.Identity;
var myvalue = id.Ticket.UserData; // "Here you are"
}
}
}
For sign in using forms you will need to write a custom cookie:
MVC -> class FormsAuthenticationService : IFormsAuthenticationService
public static void SetAuthenticationCookie(HttpContextBase context, FormsAuthenticationTicket ticket)
{
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName)
{
Value = FormsAuthentication.Encrypt(ticket),
Secure = FormsAuthentication.RequireSSL,
Domain = FormsAuthentication.CookieDomain,
HttpOnly = true,
Expires = DateTime.Now.AddMinutes(15)
};
if (!context.Request.IsSecureConnection && FormsAuthentication.RequireSSL)
{
throw new HttpException("Ticket requires SSL.");
}
context.Response.Cookies.Add(cookie);
}
public static FormsAuthenticationTicket CreateTicket(HttpContextBase context, string emailAddress, string userData, bool persist)
{
return new FormsAuthenticationTicket(1, emailAddress, DateTime.Now, DateTime.Now.AddMinutes(15), persist, userData, FormsAuthentication.FormsCookiePath);
}
Finally in SignIn you would now create the required ticket by calling CreateTicket(...), and then you would write it out by SetAuthenticationCookie(...).
public void SignIn(string userName, string password)
{
if(CheckUserValid(userName,password, out string email))
{
var ticket = CreateTicket(email, "Here you are", true);
SetAuthenticationCookie(HttpContext.Current.Base(), ticket);
}
}
I have never used it, but assume that session state is assigned during the AcquireRequestState:
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}
I had this same issue of needing to access session in global.asax and finally solved it by moving my code into the AcquireRequestState handler, which happens after the authentication is passed.
protected void Application_AcquireRequestState(Object sender, EventArgs e)
{
if (Request.IsAuthenticated && Context.Session != null)
{
// access Context.Session
}
}
This fires a lot and the current context does not always have a valid session object, hence the check.
EDIT: Had to add the check for IsAuthenticated too -- was getting a null error when logged out. Works great now.