Changing visibility of Log-out button from serverasp - asp.net

I'm now building a site including database of users. I want to add "log-out" button on the menu if the session exists. I thought that after checking session exist I would change the visibility property in the css. How can I do that. thanks.

Ok how about something like this:
javascript:
PageMethods.IsSessionActive(isActive, onSuccess, onError);
function onSuccess(result) {
if (result == "true") {
//logic where the logout button is set to visible
} else {
//set to hidden
}
}
C# server side web method:
[WebMethod] public static string IsSessionActive(string isActive) {
//check if session is active //is active set isActive = "true";
return isActive; }

Related

Await method before app starts in the same UI thread

I'm trying to check which page should load my app at the beginning, first of all I check a database table if I find the login information stored I want to push the once named StartPage(), as I'm working with the database the method includes an await if there isn't any data stored I want to push the LoginPage(). I have tried following this example Xamarin.Forms Async Task On Startup . My code is :
public App()
{
int result;
InitializeComponent();
ThreadHelper.Init(SynchronizationContext.Current);
ThreadHelper.RunOnUIThread(async () => {
MainPage = new ActivityIndicatorPage();
result = await InitializeAppAsync();
if (result == 0)
{
PushLoginPage();
}
else
{
PushStartPage();
}
});
}
public void PushStartPage()
{
NavigationPage nav = new NavigationPage(new StartPage());
nav.SetValue(NavigationPage.BarBackgroundColorProperty, Color.FromHex("#D60000"));
MainPage = nav;
}
public void PushLoginPage()
{
MainPage = new Login();
}
public void PushLoginPage(string email, string password)
{
MainPage = new Login(email, password);
}
private async Task<int> InitializeAppAsync()
{
if (ViewModel == null)
ViewModel = new MainViewModel(this);
return await ViewModel.LoginViewModel.PushInitialPage();
}
But throws the following exception and as the author of the article says, is not recommended to do it.
Exception
Another option tried was overriding the OnStart() method but didn't work either.
protected override async void OnStart()
{
Task.Run(async ()=> { await InitializeAppAsync(); });
}
The PushInitialPage method:
public async Task PushInitialPage()
{
if (_app.Properties.ContainsKey("isLogged"))
{
var user = await UserDataBase.GetUserDataAsync();
var result = await Login(user.Email, user.Password);
if (result.StatusCode != 200)
{
return 0;
///PushLoginPage();
}
else
{
return 1;
//PushStartPage();
}
}
else
{
return 0;
}
}
When the OS asks your app to show a page, it must show a page. It can't say "hold on a minute or two while I talk to this remote server over an iffy network connection." It has to show a page Right Now.
So, I recommend bringing up a splash page - your company or app logo, for example. When the splash page shows, then call InitializeAppAsync, and based on the result, switch to the login or start page or nice user-friendly offline error page.
In Xamarin.Forms we have properties called 'Application.Current.Properties'. By using this we can able to save the any data type. So once user login in to the application you can set one flag and set it is true. Then after every time when user login in to the application you can check this flag and navigate your respective page.
Sample Code :
App.cs :
public App()
{
if (Current.Properties.ContainsKey("isLogged"))
{
if((bool)Application.Current.Properties["isLogged"])
{
// navigate to your required page.
}
else
{
// naviate to login page.
}
}
else
{
// naviate to login page.
}
}
At first time application open it checks the 'isLogged' property is presented or not, if not it will move to the login page. When user login into the application by using his credentials, we need to create 'isLoggin' property and set as true. Then after if user try to login it checks the condition and navigates to the respective page.
Saving Property SampleCode :
Application.Current.Properties["isLogged"] = true;
await Application.Current.SavePropertiesAsync();
write above code for after login into the application. If a user log out from the app you need to set 'isLogged' flag is false.

OidcClient2 - Closing IBrowser while waiting for LoginAsync

Currently I am developing a Xamarin App which is using IdentityModel.OidcClient to authenticate against my server, and it is being done using the automatic mode presented on the documentation (https://github.com/IdentityModel/IdentityModel.OidcClient2). Everything is working just fine as var result = await client.LoginAsync();
is returning the LoginResult with the AccessToken, etc.
What I am trying to figure out is how the backbutton, the recent apps button (both on android) and the close button on ChromeCustomTabsBrowser should be handled since these three actions close the Ibrowser attached to the oidcClient without returning a response and will keep me stuck awaiting for a response preventing me to process with the rest of the code validations.
private async Task SignInAsync() {
IsBusy = true;
await Task.Delay(500);
try {
LoginResult result = await IdentityService.LoginAsync(new LoginRequest());
if (result == null) {
OnError(noInternetErrorMessage);
IsBusy = false;
return;
}
if (result.IsError) {
OnError(result.Error);
} else {
string userName = result.User.Claims.Where(claim => claim.Type == userNameClaimType).Select(claim => claim.Value).SingleOrDefault();
_UserToken = IdentityService.CreateOrUpdateUserToken(userName, result);
if (_UserToken != null) {
await NavigationService.NavigateToAsync<LockScreenViewModel>();
} else {
OnError(errorMessage);
}
}
} catch (Exception e) {
OnError(e.ToString());
}
IsBusy = false;
}
In the previous block of code I can't reach if (result == null) if those buttons where clicked which in turn will prevent me from removing the ActivityIndicator in the loginView and provide the login button to the user so he can try login again.
This happens because your IdentityService.LoginAsync() task is actually still waiting in the background for the custom tabs activity callback to happen, regardless of the fact that the custom tabs browser is no longer visible. Because the user closed before completing the login roundtrip, no callback will be triggered until the user completes the roundtrip in a future attempt. Each login attempt will create a new awaiting task, so the collection of waiting tasks will grow each time the user closes the custom tabs window prematurely.
At the time the user actually finishes a login roundtrip it becomes clear that the tasks are all still waiting, because they all at once unfreeze when the long awaited callback finally occurs. This poses another issue to handle, because all but the last task will result in an 'invalid state' oidc error result.
I resolved this by canceling the previous task just before starting a new login attempt. I added a TryCancel method to ChromeCustomTabsBrowser on a custom interface IBrowserExtra. In the ChromeCustomTabsBrowser.InvokeAsync implementation, a reference is kept to the TaskCompletionSource to be returned.
The next time the user clicks the sign in button, TryCancel is first invoked before ChromeCustomTabsBrowser.LoginAsync to unlock the previous login attempt still awaiting, using the kept reference.
To make this work, IsBusy=True should be postponed until after the custom tabs callback (custom tabs browser will be on top anyway), to keep the gui interactive in case the custom tabs close button was clicked. Otherwise the user will never be able to reattempt login.
Update: added sample code as requested.
public interface IBrowserExtra
{
void TryCancel();
}
public class ChromeCustomTabsBrowser : IBrowser, IBrowserExtra, IBrowserFallback
{
private readonly Activity _context;
private readonly CustomTabsActivityManager _manager;
private TaskCompletionSource<BrowserResult> _task;
private Action<string> _callback;
public ChromeCustomTabsBrowser()
{
_context = CrossCurrentActivity.Current.Activity;
_manager = new CustomTabsActivityManager(_context);
}
public Task<BrowserResult> InvokeAsync(BrowserOptions options)
{
var builder = new CustomTabsIntent.Builder(_manager.Session)
.SetToolbarColor(Color.Argb(255, 0, 0, 0))
.SetShowTitle(false)
.EnableUrlBarHiding()
.SetStartAnimations(_context, Android.Resource.Animation.SlideInLeft, Android.Resource.Animation.SlideOutRight)
.SetExitAnimations(_context, Android.Resource.Animation.SlideInLeft, Android.Resource.Animation.SlideOutRight);
var customTabsIntent = builder.Build();
// ensures the intent is not kept in the history stack, which makes
// sure navigating away from it will close it
customTabsIntent.Intent.AddFlags(ActivityFlags.NoHistory);
_callback = null;
_callback = url =>
{
UnsubscribeFromCallback();
_task.TrySetResult(new BrowserResult()
{
Response = url
});
};
SubscribeToCallback();
// Keep track of this task to be able to refer it from TryCancel later
_task = new TaskCompletionSource<BrowserResult>();
customTabsIntent.LaunchUrl(_context, Android.Net.Uri.Parse(options.StartUrl));
return _task.Task;
}
private void SubscribeToCallback()
{
OidcCallbackActivity.Callbacks += _callback;
}
private void UnsubscribeFromCallback()
{
OidcCallbackActivity.Callbacks -= _callback;
_callback = null;
}
void IBrowserExtra.TryCancel()
{
if (_callback != null)
{
UnsubscribeFromCallback();
}
if (_task != null)
{
_task.TrySetCanceled();
_task = null;
}
}
}
public class LoginService
{
private static OidcClient s_loginClient;
private Task<LoginResult> _loginChallengeTask;
private readonly IBrowser _browser;
private readonly IAppInfo _appInfo;
public LoginService(
IBrowser secureBrowser,
IBrowserFallback fallbackBrowser,
IAppInfo appInfo)
{
_appInfo = appInfo;
_browser = ChooseBrowser(appInfo, secureBrowser, fallbackBrowser);
}
private IBrowser ChooseBrowser(IAppInfo appInfo, IBrowser secureBrowser, IBrowserFallback fallbackBrowser)
{
return appInfo.PlatformSupportsSecureBrowserSession ? secureBrowser : fallbackBrowser as IBrowser;
}
public async Task<bool> StartLoginChallenge()
{
// Cancel any pending browser invocation task
EnsureNoLoginChallengeActive();
s_loginClient = OpenIdConnect.CreateOidcClient(_browser, _appInfo);
try
{
_loginChallengeTask = s_loginClient.LoginAsync(new LoginRequest()
{
FrontChannelExtraParameters = OpenIdConnectConfiguration.LoginExtraParams
});
// This triggers the custom tabs browser login session
var oidcResult = await _loginChallengeTask;
if (_loginChallengeTask.IsCanceled)
{
// task can be cancelled if a second login attempt was completed while the first
// was cancelled prematurely even before the browser view appeared.
return false;
}
else
{
// at this point we returned from the browser login session
if (oidcResult?.IsError ?? throw new LoginException("oidcResult is null."))
{
if (oidcResult.Error == "UserCancel")
{
// Graceful exit: user canceled using the close button on the browser view.
return false;
}
else
{
throw new LoginException(oidcResult.Error);
}
}
}
// we get here if browser session just popped and navigation is back at customer page
PerformPostLoginOperations(oidcResult);
return true;
}
catch (TaskCanceledException)
{
// swallow cancel exception.
// this can occur when user canceled browser session and restarted.
// Previous session is forcefully canceled at start of ExecuteLoginChallenge cauing this exception.
LogHelper.Debug($"'Login attempt was via browser roundtrip canceled.");
return false;
}
}
private void EnsureNoLoginChallengeActive()
{
if (IsLoginSessionStarted)
{
(_browser as IBrowserExtra)?.TryCancel();
}
}
private static bool IsLoginSessionStarted => s_loginClient != null;
}

SignalR - correct implementation of chat

I need to implement chat on my web project. How to implement it on one page - there are many articles about it. But I need to have ability :
1. Notify other users, that somebody logged to site (on any page, not only on chat page)
2. Notify other users, that somebody logout
So, I have the following code of hub:
public void Connect()
{
try
{
var id = Context.ConnectionId;
string username = Context.User.Identity.Name;
var currentUser = connectedUsers.Where(p => p.Username == username).FirstOrDefault();
if (currentUser == null)
{
AddNewUserToCollection();
}
else
{
// update ConnectionId for sure (connection id is changed sometimes (probably if user is logged out and login again))
if (currentUser.ConnectionId != id)
{
var companyId = _chatRepository.GetCompanyIdOfUser(username); // throws exception if companyId is null
Groups.Remove(currentUser.ConnectionId, companyId.ToString());
Groups.Add(id, companyId.ToString());
currentUser.ConnectionId = id;
//Clients.Group(companyId.ToString()).onNewUserConnected(username);
}
}
}
catch(InvalidCompanyException c_ex)
{
Clients.Client(Context.ConnectionId).onErrorMessage($"User '{c_ex.Username}' does not exist");
}
}
public void Disconnect()
{
string username = Context.User.Identity.Name;
var item = connectedUsers.Where(p => p.Username == username).FirstOrDefault();
if (item != null)
{
connectedUsers.Remove(item);
Groups.Remove(item.ConnectionId, item.CompanyID.ToString());
Clients.Group(item.CompanyID.ToString()).onUserDisconnected(item.Username);
}
}
public override Task OnDisconnected(bool stopCalled)
{
var item = connectedUsers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault();
if (item != null)
{
connectedUsers.Remove(item);
Groups.Remove(item.ConnectionId, item.CompanyID.ToString());
Clients.Group(item.CompanyID.ToString()).onUserDisconnected(item.Username);
}
return base.OnDisconnected(stopCalled);
}
and I added the following code to _layout.cshtml:
<script>
$(document).ready(function () {
var chat = $.connection.chatHub;
$.connection.hub.start().done(function () {
chat.server.connect();
});
});
</script>
to notify other users, that the current user is logged. But debugger says, that pair OnDisconnected/Connect is called every time, when user reload page (go thru pages) with different connectionId. When I remove this client code - that pair is not called. How to implement it correctly, to notify other users, that somebody is online, but without reconnect each time?
Since you have the connect() call in a razor (_layout.cshtml) page, you will effectively be disconnecting/connecting on every post back (page load).
The scenario you're trying to use is best in a SPA (or AJAX) scenario where navigation is handled asynchronously by client side JavaScript. Your current setup is refreshing the screen, reloading the JavaScript, re-running the document ready() function with each server rendered navigation.
Another alternative is to use the client's actual user Id, and pass that to the server.connect(id) method. Then use this user Id to track the user activity instead of the hub ConnectionId.

Jxbrowser 6.2 proxy authentication

The dialog that displays when using this code does not have a username and password textboxes. Is this a bug or am I doing something wrong?
browser.getContext().getNetworkService().setNetworkDelegate(new DefaultNetworkDelegate() {
#Override
public boolean onAuthRequired(AuthRequiredParams params) {
if (params.isProxy()) {
params.setUsername("proxy-username");
params.setPassword("proxy-password");
return false;
}
return true;
}
});
This code doesn't display a dialog. This code just sets username and password values and return. If you need to display login dialog, then you don't need to register NetworkDelegate.

Checking if page is valid without firing validations from server side

I want to check if current page is valid for a validation group without showing any validation messages. If I call Page.Validate("ValidationGroup") then it shows all the valiation message but I do not want it.
I just to check if page is valid for a particular validation group. And one more constraint, I have to do this on server side can't do it with javascript.
You can loop through the validators in a validation group, like this:
private bool AreAllValidatorsInGroupValid(string validationGroupName)
{
foreach(var theValidator in Page.GetValidators(validationGroupName))
{
var baseValidator = theValidator as BaseValidator;
if(baseValidator != null)
{
if(!baseValidator.IsValid)
{
return false;
}
}
}
return true;
}
Usage:
if(!AreAllValidatorsInGroupValid("ValidationGroup"))
{
// Do something here
}

Resources