Prism Event Aggregator Not Working With Async/Await - prism

I am working with prism in a client server app with sql server. I have a loading screen after login screen in which I've fetch the main data in async task for main windows and publish it and subscribe in main windows like customers, Users and etc. But the problem is that subscriber not updated. But If I sign out and sign in again then subscriber updated.
Subscriber not updated first time.
Here is the code of loading screen
public class StartPageViewModel : ViewModelBase
{
private readonly IUnitOfWork _unitOfWork;
private readonly IEventAggregator _eventAggregator;
private readonly IRegionManager _regionManager;
public List<Customer> Customers { get; set; }
private List<Models.User> Users { get; set; }
private List<Invoice> Invoices { get; set; }
public List<Vehicle> Vehicles { get; set; }
public List<Tax> Taxes { get; set; }
private Models.User _user;
private object _userId;
public StartPageViewModel(IRegionManager regionManager, Models.User user,
IUnitOfWork unitOfWork, IEventAggregator eventAggregator)
{
_regionManager = regionManager;
_user = user;
_unitOfWork = unitOfWork;
_eventAggregator = eventAggregator;
Customers = new List<Customer>();
Users = new List<Models.User>();
Invoices = new List<Invoice>();
Vehicles = new List<Vehicle>();
Taxes = new List<Tax>();
}
[OnCommand("InitializeStartPage")]
public async void InitializeStartPage()
{
if (!InternetCs.IsConnectedToInternet())
_regionManager.RequestNavigate(RegionNames.ShellRegion, "InternetConnection");
else
{
await Task.WhenAll(CheckUser(), Preloading()).ContinueWith(async(t, _) =>
{
_eventAggregator.GetEvent<AllCustomersEvent>().Publish(Customers);
_eventAggregator.GetEvent<AllInvoicesEvent>().Publish(Invoices);
_eventAggregator.GetEvent<CurrentUserEvent>().Publish(_user);
_eventAggregator.GetEvent<AllUsersEvent>().Publish(Users);
_eventAggregator.GetEvent<AllVehiclesEvent>().Publish(Vehicles);
_eventAggregator.GetEvent<AllTaxesEvent>().Publish(Taxes);
if (_user != null && _user.Status)
{
_user.LastLogin = DateTime.Now;
_user.LoginStatus = true;
_unitOfWork.UserRepository.Update(_user);
await _unitOfWork.SaveAsync();
_regionManager.RequestNavigate(RegionNames.MainContentRegion, "Home");
_regionManager.RequestNavigate(RegionNames.ShellRegion, "MainWindow");
}
else
{
_regionManager.RequestNavigate(RegionNames.ShellRegion, "LoginWindow");
}
}, null, TaskScheduler.FromCurrentSynchronizationContext());
}
}
private async Task<Models.User> CheckUser()
{
IsoStorage.Instance.TryGetValue("UserId", out _userId);
_user = await _unitOfWork.UserRepository.GetAsync((int)_userId);
return _user;
}
private async Task Preloading()
{
Customers = await _unitOfWork.CustomerRepository.GetAsync();
Invoices = await _unitOfWork.InvoiceRepository.GetAsync();
Users = await _unitOfWork.UserRepository.GetAsync();
Vehicles = await _unitOfWork.VehicleRepository.GetAsync();
Taxes = await _unitOfWork.TaxRepository.GetAsync();
}
}
and here is example subscriber
public AdminProfileViewModel(IEventAggregator eventAggregator)
{
Users = new List<Models.User>();
eventAggregator.GetEvent<AllUsersEvent>().Subscribe(AdminAllUsers, ThreadOption.PublisherThread);
}
private void AdminAllUsers(List<Models.User> obj)
{
Users = obj;
}

Related

ItemsSource doesn't show/bind when ObservableCollection is filled before loading the page

I have a carouselview, in that view I have an ObservableCollection binded as an itemssource. I am able to bind the collection and it would show when I execute the viewmodel's command in the OnAppearing event.
Code that works:
Second Page
public partial class SecondPage : ContentPage
{
public Coll(bool hard, string subject)
{
InitializeComponent();
var vm = (DataSelectionViewModel)BindingContext;
vm.Hard = hard;
vm.Subject = subject;
/* had to set "hard" and "subject" here again, otherwise data won't load */
}
protected override async void OnAppearing()
{
var vm = (DataSelectionViewModel)BindingContext;
base.OnAppearing();
await vm.LoadData.ExecuteAsync().ConfigureAwait(false);
}
}
The viewmodel for second page
public class DataSelectionViewModel : BaseViewModel
{
private string subject;
public string Subject { get => subject; set => SetProperty(ref subject, value); }
private bool hard;
public bool Hard { get => hard; set => SetProperty(ref hard, value); }
public ObservableCollection<Items> FilteredData { get; set; }
public UserSelectionViewModel()
{
_dataStore = DependencyService.Get<IDataStore>();
LoadData= new AsyncAwaitBestPractices.MVVM.AsyncCommand(FilterData);
FilteredData = new ObservableCollection<Items>();
}
public async Task FilterData()
{
FilteredData.Clear();
var filtereddata = await _dataStore.SearchData(Hard, Subject).ConfigureAwait(false);
foreach (var data in filtereddata)
{
FilteredData.Add(data);
}
}
}
First Page where second page gets Hard and Subject values
private async void ButtonClick(object sender, EventArgs e)
{
var vm = (BaseViewModel)BindingContext;
vm.Hard = HardButtonSelected == Hard;
vm.Subject = vm.Subject.ToLower();
await Navigation.PushAsync(new SecondPage(vm.Hard, vm.Subject));
}
So I want to change my code so that if I press the button on the first page, data instantly starts to filter and add to the ObservableCollection and when it's finished, then navigate to the second page. However if I try to load it to the BaseViewModel and then get the data from the second viewmodel it won't show the data.
Code that doesn't work:
Second Page
public partial class SecondPage : ContentPage
{
public SecondPage()
{
InitializeComponent();
}
}
The viewmodel for second page
public class DataSelectionViewModel : BaseViewModel
{
public ObservableCollection<Items> FilteredData { get; set; }
public UserSelectionViewModel()
{
FilteredData = new ObservableCollection<Items>();
}
}
BaseViewModel
public class BaseViewModel : INotifyPropertyChanged
{
private string subject;
public string Subject { get => subject; set => SetProperty(ref subject, value); }
private bool hard;
public bool Hard { get => hard; set => SetProperty(ref hard, value); }
public ObservableCollection<Items> FilteredData { get; set; }
/* BaseViewModel has implementation of SetProperty */
}
First Page where second page gets Hard and Subject values
private async void ButtonClick(object sender, EventArgs e)
{
var vm = (BaseViewModel)BindingContext;
vm.Hard = HardButtonSelected == Hard;
vm.Subject = vm.Subject.ToLower();
}
First Page viewmodel
public class FirstPageViewModel : BaseViewModel
{
public IAsyncCommand MehetButtonClickedCommand { get; }
readonly IPageService pageService;
readonly IFeladatokStore _feladatokStore;
public FeladatValasztoViewModel()
{
_dataStore = DependencyService.Get<IDataStore>();
ButtonClickedCommand = new AsyncCommand(ButtonClicked);
pageService = DependencyService.Get<IPageService>();
}
private async Task ButtonClicked()
{
await FilterData();
await pageService.PushAsync(new SecondPage());
}
private async Task FilterData()
{
FilteredData.Clear();
var datas = await _dataStore.SearchData(Subject, Hard).ConfigureAwait(false);
foreach (var data in datas)
{
FilteredData.Add(data);
}
}
So basically this gives a null exception error. I also tried giving the ObservableCollection as an argument for SecondPage(ObservableCollection x) and that did work, but because I had to make another ObservableCollection for it and copy from one to another it stopped being async and froze for a couple of seconds. So my question is how can I make this async?
To avoid delay, build the new collection in a private variable. Then set the property to that variable:
// Constructor with parameter
public SomeClass(IList<Items> data)
{
SetFilteredDataCopy(data);
}
public ObservableCollection<Items> FilteredData { get; set; }
private void SetFilteredDataCopy(IList<Items> src)
{
var copy = new ObservableCollection<Items>();
foreach (var item in src)
copy.Add(item);
FilteredData = copy;
//MAYBE OnPropertyChanged(nameof(FilteredData));
}

Xamarin Forms consuming Web Service

I'm new in mobile apps and now developing an app with xamarin forms. There is a website which i developed with django (sqlite3 db), and now i'am trying to consume data from it and display in my mobile app in listvew. Any thoughts how to achieve it. I've tried this but it doesn't work. Should i use rest api?
public class LandingViewModel : INotifyPropertyChanged
{
private List<Dishes> _menuList { set; get; }
public List<Dishes> MenuList
{
get
{
return _menuList;
}
set
{
if(value != _menuList)
{
_menuList = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public LandingViewModel()
{
GetDataAsync();
}
private async void GetDataAsync()
{
HttpClient client = new HttpClient();
var response = await client.GetAsync("https://mysite.ru/project/");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var menu = JsonConvert.DeserializeObject<List<Dishes>>(content);
MenuList = new List<Dishes>(menu);
}
}
models:
public class Dishes
{
public int id { get; set; }
public string description { get; set; }
public string image { get; set; }
public DateTime published { get; set; }
}
my database in django:
operations = [
migrations.CreateModel(
name='Post',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.TextField(blank=True)),
('image', models.ImageField(blank=True, upload_to='pictures/')),
('published', models.DateTimeField(verbose_name='publishing date')),
],
),
]
i solved the problem
in postgresql database allowed remote connection: in postgresql.conf replaced line listen_addresses = 'localhost' with listen_addresses = '*'
allowed tcp\ip connection on port 5432
in my web api established connection width db
NpgsqlConnection connection;
public string _name;
public string _description;
public string _image;
private readonly MenuContext _context;
public MenuController(MenuContext context)
{
_context = context;
string connectionString = "Server=server; Port=5432; User Id=user;
Password=password; Database=database";
try
{
connection = new NpgsqlConnection(connectionString);
connection.Open();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
NpgsqlCommand command = connection.CreateCommand();
command.CommandText = "SELECT * FROM table";
try
{
NpgsqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
_name = reader[1].ToString();
_image = reader[2].ToString();
_description = reader[3].ToString();
_context.Menus.Add(new Menu { name = _name, description =
_description, image = "https://mysite.ru/media/" + _image });
_context.SaveChanges();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
// GET: api/Menu
[HttpGet]
public async Task<ActionResult<IEnumerable<Menu>>> GetMenus()
{
return await _context.Menus.ToListAsync();
}
code in my app:
private async void GetDataAsync()
{
HttpClient httpClient = new HttpClient();
var content = await httpClient.GetStringAsync("https://locahost/api/Menu");
var menu = JsonConvert.DeserializeObject<List<Dishes>>(content);
MenuList = new ObservableCollection<Dishes>(menu);
}
and then displayed it in listview

How join List<Class> with IEnumerable<Class>?

I have the following classes.
public class Course
{
public string CourseNumber { get; set; }
public List<PriceGroup> PriceGroups { get; set; }
}
public class PriceGroup
{
public int Id { get; set; }
public string CourseNumber { get; set; }
}
I have a service that fetches data from the database. Courses is an IEnumerable<Course> and priceGroups is a IEnumerable<PriceGroup>. As you can see in the Course class, a course has a List<PriceGroup>. I need to somehow add each PriceGroup in the IEnumerable<PriceGroup> to the list in each course in the IEnumerable<Course> if they match on the variable CourseNumber. So I will end up with a correct Course containing the right List<PriceGroup>'s
public async Task<IEnumerable<Course>> GetAllAsync()
{
//courses is an IEnumerable<Course>
var courses = await _courseRepository.GetAllAsync();
//priceGroups is an IEnumerable<PriceGroup>
var priceGroups = await _coursePriceGroupRepository.GetAllAsync();
courses.GroupJoin(priceGroups, c => c.PriceGroups.Select(i => i.CourseNumber), pg => pg.CourseNumber, (c, pg) => new
{
});
return await courses;
}
To do this I've tried to do a GroupJoin but without success. I have not finished the attempt as I am completely stuck mentally. Perhaps I am trying to do something that is not possible with a GroupJoin. Does anyone know a way to achieve what I need?
So you want all (or some) Courses, each Course with all (or some of) its PriceGroups.
There is a straightforware one-to-many relation betweeen Courses and PriceGroups: Every Course has zero or more PriceGroups, every PriceGroup belongs to exactly one Course, namely the Course that foreign key CourseNumber refers to.
You are right, whenever you want items with their sub-items you use GroupJoin.
public async Task<IEnumerable<Course>> GetAllAsync()
{
IEnumerable<Course> courses = await _courseRepository.GetAllAsync();
IEnumerable<PriceGroup> priceGroups = await _coursePriceGroupRepository.GetAllAsync();
var queryCoursesWithPriceGroups = courses.GroupJoin( // GroupJoin Courses
priceGroups, // with PriceGroups
course => course.CourseNumber, // from every Course take primary key
priceGroup => priceGroup.CourseNumber, // from every PriceGroup take foreign key
(course, priceGroupsOfThisCourse) => new // from every Course with
{ // its priceGroups make one new
// Select the Course properties you plan to use:
Id = course.Id,
Name = course.Name,
StartDate = course.StartDate,
...
PriceGroups = priceGroupsOfThisCourse.Select(priceGroup => new
{
// Select only the PriceGroup properties that you plan to use
Id = priceGroup.Id,
Name = priceGroup.Name,
...
// not needed, you know the value:
// CourseId = priceGroup.CourseId
})
.ToList(),
});
// Note: this is a query. It is not executed yet!
return await queryCoursesWithPriceGroups.ToListAsync();
//Assuming courseNumber is unique in Courses table
return Courses.Select( c=> { c.PriceGroup=priceGroup.Where(p=>p.CourseNumber==c.CourseNumber).ToList(); return c; });
I did a practical example, obviously you should substitute the fake methods with repository ones:
class Program
{
static async void Main(string[] args)
{
var courses = GetAllAsync().Result;
}
private static async Task<IEnumerable<Course>> GetAllAsync()
{
//courses is an IEnumerable<Course>
var courses = await GetCoursesAsync();
//priceGroups is an IEnumerable<PriceGroup>
var priceGroups = await GetPriceGroups();
foreach (var course in courses)
{
foreach (var priceGroup in priceGroups.Where(x => x.CourseNumber == course.CourseNumber))
{
course.PriceGroups.Add(priceGroup);
}
}
return courses;
}
private static async Task<IEnumerable<Course>> GetCoursesAsync()
{
return await Task.FromResult<IEnumerable<Course>>(
new List<Course>() {
new Course{
CourseNumber = "PIZZA1",
PriceGroups = new List<PriceGroup>()
},
new Course{
CourseNumber = "PIZZA2",
PriceGroups = new List<PriceGroup>()
},
new Course{
CourseNumber = "PIZZA3",
PriceGroups = new List<PriceGroup>()
},
}
);
}
private static async Task<IEnumerable<PriceGroup>> GetPriceGroups()
{
return await Task.FromResult<IEnumerable<PriceGroup>>(
new List<PriceGroup>() {
new PriceGroup{
Id = 1,
CourseNumber = "PIZZA1"
},
new PriceGroup{
Id = 2,
CourseNumber = "PIZZA2"
},
new PriceGroup{
Id = 3,
CourseNumber = "PIZZA3"
}
}
);
}
}
public class Course
{
public string CourseNumber { get; set; }
public List<PriceGroup> PriceGroups { get; set; }
}
public class PriceGroup
{
public int Id { get; set; }
public string CourseNumber { get; set; }
}
You should avoid using IEnumerable when you return data from DB, you can incur in unexpected behaviours. I suggest you this approach:
class Program
{
static void Main(string[] args)
{
var courses = GetAllAsync().Result;
}
private static async Task<List<Course>> GetAllAsync()
{
var courses = await GetCoursesAsync();
var priceGroups = await GetPriceGroups();
courses.ForEach(x => { x.PriceGroups.AddRange(priceGroups.Where(y => y.CourseNumber == x.CourseNumber)); });
return courses;
}
private static async Task<List<Course>> GetCoursesAsync()
{
return await Task.FromResult(
new List<Course>() {
new Course{
CourseNumber = "PIZZA1",
PriceGroups = new List<PriceGroup>()
},
new Course{
CourseNumber = "PIZZA2",
PriceGroups = new List<PriceGroup>()
},
new Course{
CourseNumber = "PIZZA3",
PriceGroups = new List<PriceGroup>()
},
}
);
}
private static async Task<List<PriceGroup>> GetPriceGroups()
{
return await Task.FromResult(
new List<PriceGroup>() {
new PriceGroup{
Id = 1,
CourseNumber = "PIZZA1"
},
new PriceGroup{
Id = 2,
CourseNumber = "PIZZA2"
},
new PriceGroup{
Id = 3,
CourseNumber = "PIZZA3"
}
}
);
}
}
public class Course
{
public string CourseNumber { get; set; }
public List<PriceGroup> PriceGroups { get; set; }
}
public class PriceGroup
{
public int Id { get; set; }
public string CourseNumber { get; set; }
}
I made a version using GroupJoin too:
class Program
{
static void Main(string[] args)
{
var courses = GetAllAsync().Result;
}
private static async Task<List<Course>> GetAllAsync()
{
var courses = await GetCoursesAsync();
var priceGroups = await GetPriceGroups();
var groupedData = courses.GroupJoin(priceGroups,
course => course.CourseNumber,
priceGroup => priceGroup.CourseNumber,
(course, priceGroupsCollection) =>
new
{
CourseNumber = course.CourseNumber,
PriceGroups = priceGroupsCollection.ToList()
});
courses.ForEach(x => { x.PriceGroups = groupedData.FirstOrDefault(y => y.CourseNumber == x.CourseNumber)?.PriceGroups ?? new List<PriceGroup>(); });
return courses;
}
private static async Task<List<Course>> GetCoursesAsync()
{
return await Task.FromResult(
new List<Course>() {
new Course{
CourseNumber = "PIZZA1",
PriceGroups = new List<PriceGroup>()
},
new Course{
CourseNumber = "PIZZA2",
PriceGroups = new List<PriceGroup>()
},
new Course{
CourseNumber = "PIZZA3",
PriceGroups = new List<PriceGroup>()
},
}
);
}
private static async Task<List<PriceGroup>> GetPriceGroups()
{
return await Task.FromResult(
new List<PriceGroup>() {
new PriceGroup{
Id = 1,
CourseNumber = "PIZZA1"
},
new PriceGroup{
Id = 2,
CourseNumber = "PIZZA2"
},
new PriceGroup{
Id = 3,
CourseNumber = "PIZZA3"
},
new PriceGroup{
Id = 4,
CourseNumber = "PIZZA1"
}
}
);
}
}
public class Course
{
public string CourseNumber { get; set; }
public List<PriceGroup> PriceGroups { get; set; }
}
public class PriceGroup
{
public int Id { get; set; }
public string CourseNumber { get; set; }
}

Sign-in user via remote services and about TokenAuthController

I need to sign-in the user using only remote services. I think using TokenAuthController in Web.Core application
I really can't understand why the snippet given below doesn't work. I have added a new method called Login in TokenAuthController .
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.MultiTenancy;
using Abp.Runtime.Security;
using Abp.UI;
using Abp.Web.Models;
using Microsoft.AspNetCore.Authorization;
using TSE.DergiAbone.Authentication.External;
using TSE.DergiAbone.Authentication.JwtBearer;
using TSE.DergiAbone.Authorization;
using TSE.DergiAbone.Authorization.Users;
using TSE.DergiAbone.Identity;
using TSE.DergiAbone.Models.TokenAuth;
using TSE.DergiAbone.MultiTenancy;
namespace TSE.DergiAbone.Controllers
{
[Route("api/[controller]/[action]")]
public class TokenAuthController : DergiAboneControllerBase
{
private readonly LogInManager _logInManager;
private readonly SignInManager _signInManager;
private readonly ITenantCache _tenantCache;
private readonly AbpLoginResultTypeHelper _abpLoginResultTypeHelper;
private readonly TokenAuthConfiguration _configuration;
private readonly IExternalAuthConfiguration _externalAuthConfiguration;
private readonly IExternalAuthManager _externalAuthManager;
private readonly UserRegistrationManager _userRegistrationManager;
public TokenAuthController(
LogInManager logInManager,
SignInManager signInManager,
ITenantCache tenantCache,
AbpLoginResultTypeHelper abpLoginResultTypeHelper,
TokenAuthConfiguration configuration,
IExternalAuthConfiguration externalAuthConfiguration,
IExternalAuthManager externalAuthManager,
UserRegistrationManager userRegistrationManager)
{
_logInManager = logInManager;
_tenantCache = tenantCache;
_abpLoginResultTypeHelper = abpLoginResultTypeHelper;
_configuration = configuration;
_externalAuthConfiguration = externalAuthConfiguration;
_externalAuthManager = externalAuthManager;
_userRegistrationManager = userRegistrationManager;
_signInManager = signInManager;
}
***[HttpPost]
public virtual async Task<JsonResult> Login(string UserName, string password,bool IsPersistent )
{
var loginResult = await GetLoginResultAsync(UserName, password, GetTenancyNameOrNull());
//var result = await _signInManager.SignInAsync(loginResult.Identity, IsPersistent);
var result = await _signInManager.PasswordSignInAsync(UserName, password, true, false);
if (result.Succeeded)
{
long bak= User.Identity.GetUserId().Value;
string res = "User signed in";
}
await UnitOfWorkManager.Current.SaveChangesAsync();
bool chk = User.Identity.IsAuthenticated;
return Json(new Abp.Web.Models.AjaxResponse { TargetUrl = "" });
}***
[HttpPost]
public async Task<AuthenticateResultModel> Authenticate([FromBody] AuthenticateModel model)
{
var loginResult = await GetLoginResultAsync(
model.UserNameOrEmailAddress,
model.Password,
GetTenancyNameOrNull()
);
//var chk = _logInManager.LoginAsync("jimycarbonare#gmail.com", "123qwe", "TSEDergi").Result;
//var chk2 = _logInManager.Login("jimycarbonare#gmail.com", "123qwe", "TSEDergi");
//var name = User.Identity.Name;
//bool bak0 = User.IsInRole("admin");
//var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
//var loginResult = await GetLoginResultAsync("jimycarbonare#gmail.com", "123qwe", "TSEDergi");
//await _signInManager.SignInAsync(loginResult.Identity, model.RememberClient);//_logInManager.LoginAsync("jimycarbonare#gmail.com", "123qwe", "TSEDergi").Result;
//var name = User.Identity.Name;
//bool bak0 = User.IsInRole("admin");
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncrpyedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResult.User.Id
};
}
[HttpGet]
public List<ExternalLoginProviderInfoModel> GetExternalAuthenticationProviders()
{
return ObjectMapper.Map<List<ExternalLoginProviderInfoModel>>(_externalAuthConfiguration.Providers);
}
[HttpPost]
public async Task<ExternalAuthenticateResultModel> ExternalAuthenticate([FromBody] ExternalAuthenticateModel model)
{
var externalUser = await GetExternalUserInfo(model);
var loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
{
var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));
return new ExternalAuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncrpyedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
};
}
case AbpLoginResultType.UnknownExternalLogin:
{
var newUser = await RegisterExternalUserAsync(externalUser);
if (!newUser.IsActive)
{
return new ExternalAuthenticateResultModel
{
WaitingForActivation = true
};
}
// Try to login again with newly registered user!
loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull());
if (loginResult.Result != AbpLoginResultType.Success)
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
GetTenancyNameOrNull()
);
}
return new ExternalAuthenticateResultModel
{
AccessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity)),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
};
}
default:
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
loginResult.Result,
model.ProviderKey,
GetTenancyNameOrNull()
);
}
}
}
private async Task<User> RegisterExternalUserAsync(ExternalAuthUserInfo externalUser)
{
var user = await _userRegistrationManager.RegisterAsync(
externalUser.Name,
externalUser.Surname,
externalUser.EmailAddress,
externalUser.EmailAddress,
Authorization.Users.User.CreateRandomPassword(),
true
);
user.Logins = new List<UserLogin>
{
new UserLogin
{
LoginProvider = externalUser.Provider,
ProviderKey = externalUser.ProviderKey,
TenantId = user.TenantId
}
};
await CurrentUnitOfWork.SaveChangesAsync();
return user;
}
private async Task<ExternalAuthUserInfo> GetExternalUserInfo(ExternalAuthenticateModel model)
{
var userInfo = await _externalAuthManager.GetUserInfo(model.AuthProvider, model.ProviderAccessCode);
if (userInfo.ProviderKey != model.ProviderKey)
{
throw new UserFriendlyException(L("CouldNotValidateExternalUser"));
}
return userInfo;
}
private string GetTenancyNameOrNull()
{
if (!AbpSession.TenantId.HasValue)
{
return null;
}
return _tenantCache.GetOrNull(AbpSession.TenantId.Value)?.TenancyName;
}
[HttpPost]
public AbpLoginResult<Tenant, User> GetLoginResult2Async(string usernameOrEmailAddress, string password, string tenancyName)
{
var loginResult = _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName).Result;
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
}
}
private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
{
var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
}
}
private string CreateAccessToken(IEnumerable<Claim> claims, TimeSpan? expiration = null)
{
var now = DateTime.UtcNow;
var jwtSecurityToken = new JwtSecurityToken(
issuer: _configuration.Issuer,
audience: _configuration.Audience,
claims: claims,
notBefore: now,
expires: now.Add(expiration ?? _configuration.Expiration),
signingCredentials: _configuration.SigningCredentials
);
return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
}
private static List<Claim> CreateJwtClaims(ClaimsIdentity identity)
{
var claims = identity.Claims.ToList();
var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier);
// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
claims.AddRange(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
});
return claims;
}
private string GetEncrpyedAccessToken(string accessToken)
{
return SimpleStringCipher.Instance.Encrypt(accessToken, AppConsts.DefaultPassPhrase);
}
}
}
I am getting a reasonable loginResult. And PasswordSignInAsync method returns with success. At that point I conclude the sign in process is OK. But after when I check User.Identity. I see it is null. Same is valid for the SignInAsync method.All I wanna do is sign-in the user only using the remote services. Thank you all..
I solved the problem as given below:
Change the httpost login method in AccountController of Web.Mvc application as below
[HttpPost]
[UnitOfWork]
public virtual async Task<JsonResult> Login(LoginViewModel loginModel, string returnUrl = "", string returnUrlHash = "")
{
var claims = GetClaims(loginModel.UsernameOrEmailAddress, loginModel.Password);
if (claims == null)//giriş yapılamadı
{
return Json(new AjaxResponse { TargetUrl = "" });
}
else
{
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name,
ClaimTypes.Role);
foreach (var claim in claims)
{
identity.AddClaim(new Claim(claim.type, claim.value));
}
//AbpSession.UserId=18;
//// Authenticate using the identity
//var principal = new ClaimsPrincipal(identity);
//await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { IsPersistent = true });
//bool chk = User.Identity.IsAuthenticated;
////bool bak = User.Identity.IsAuthenticated;
//bool bak2 = User.IsInRole("Admin");
//return RedirectToAction("Index", "Home");
await _signInManager.SignInAsync(identity, loginModel.RememberMe);
await UnitOfWorkManager.Current.SaveChangesAsync();
bool bak = User.Identity.IsAuthenticated;
var bakl = AbpSession.UserId;
}
returnUrl = NormalizeReturnUrl(returnUrl);
if (!string.IsNullOrWhiteSpace(returnUrlHash))
{
returnUrl = returnUrl + returnUrlHash;
}
return Json(new AjaxResponse { TargetUrl = returnUrl });
}
Create GetClaims method in AccountController of Web.Mvc application
protected List<ClaimRootObject> GetClaims(string UserName, string Password)
{
using (var client = new HttpClient())
{
string reqString = "http://localhost:21021/api/" + "TokenAuth/GetClaims/GetClaims?UserName=" + UserName + "&password=" + Password + "&TenantName=Default";
//string reqString = "http://localhost:81/api/TokenAuth/GetClaims/GetClaims?UserName=admin&password=123qwe&TenantName=TSEDergi";
HttpResponseMessage response = client.GetAsync(reqString).Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
// Get the response
var JsonString = response.Content.ReadAsStringAsync();
// Deserialise the data (include the Newtonsoft JSON Nuget package if you don't already have it)
//List<Claim> deserialized = JsonConvert.DeserializeObject<List<Claim>>(JsonString.Result);
List<ClaimRootObject> deserialized = JsonConvert.DeserializeObject<List<ClaimRootObject>>(JsonString.Result);
if (deserialized != null)
{
return deserialized;
}
}
else
{
}
}
return null;
}
Create the required objects
public class ClaimRootObject
{
public string issuer { get; set; }
public string originalIssuer { get; set; }
public Properties properties { get; set; }
public Subject subject { get; set; }
public string type { get; set; }
public string value { get; set; }
public string valueType { get; set; }
}
public class Properties
{
}
public class Subject
{
public string authenticationType { get; set; }
public bool isAuthenticated { get; set; }
public object actor { get; set; }
public object bootstrapContext { get; set; }
public List claims { get; set; }
public object label { get; set; }
public string name { get; set; }
public string nameClaimType { get; set; }
public string roleClaimType { get; set; }
}
And last step, modify your startup class of Web.Mvc project to enable cookie authentication.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// MVC
services.AddMvc(
options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())
);
#region cookieAuthentication
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
#endregion cookieAuthentication
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
services.AddScoped();
services.AddSignalR();
// Configure Abp and Dependency Injection
return services.AddAbp(
// Configure Log4Net logging
options => options.IocManager.IocContainer.AddFacility(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
)
);
}
That's all. Then you can log in a user into the application using only remote services..

Prism 5 to 6.2 - InteractionRequest - InvocationList not null anymore when navigate to new object

PRISM 6.2 / EntityFramework 6.3.1 / StockTrader UI / UnityContainer
I acutally having a project with PRISM 5.0.0 and want to update to PRISM 6.2. The project runs fine on 5.0.0, but when I'm updating to 6.2 I got the following problem with the InteractionRequest.
When I navigate to a view/viewmodel with Notifications for the first time, everything works and I can handle the InteractionRequests as usual. If I navigate back and navigate to the view again with a new object, the InteractionsRequest raised the notification twice. (...navigating back and go to again -> raised three times and so on).
In some reasons, the message "This Visual is not connected to a PresentationSource" will occur.
I figure out, that the _invocationCount and _invocationList on the InteractionRequest will not be set to "0"/"null" with PRISM 6.2. So, i think the InteractionRequest will call the notification more than one time. Attached, are screenshots from PRISM 5 and PRISM 6.2.
How can I handle this and solve the problem. In my opinion, it's not a big thing but I actually spent a lot of time to find a solution. Thanks...
PRISM 5.0.0 - working fine
PRISM 6.2 - issue
2017.02.22 Added Sourccode. Software is used to handle devices in datacenters. I deleted all unnecessary sourcecode, but with these files the problem still occur. Perhaps this is a try to find my issue....
Rackmodule.cs
-> Initialize Module Rack
public class RackModule : IModule
{
private readonly IRegionManager _regionManager;
private readonly IUnityContainer _container;
public RackModule(IRegionManager regionManager, IUnityContainer container)
{
_regionManager = regionManager;
_container = container;
}
public void Initialize()
{
_container.RegisterType<IRackViewModel, RackViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<IRackToolbarViewModel, RackToolbarViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<IRackStatusbarViewModel, RackStatusbarViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<IRackSummaryViewModel, RackSummaryViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<IGeneralDataViewModel, GeneralDataViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<IPlanDataViewModel, PlanDataViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<IRackDataViewModel, RackDataViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<Object, GeneralDataView>(typeof(GeneralDataView).FullName);
IRegion region = this._regionManager.Regions["MainRegion"];
var rackView = _container.Resolve<RackView>();
region.Add(rackView, "RackView");
region.Activate(rackView);
IRegion toolbarregion = this._regionManager.Regions["RackToolbarRegion"];
var toolbarView = _container.Resolve<RackToolbarView>();
toolbarregion.Add(toolbarView, "RackToolbarView");
toolbarregion.Activate(toolbarView);
IRegion statusbarregion = this._regionManager.Regions["RackStatusbarRegion"];
var statusbarView = _container.Resolve<RackStatusbarView>();
statusbarregion.Add(statusbarView, "RackStatusbarView");
statusbarregion.Activate(statusbarView);
_container.RegisterType<Object, RackSummaryView>(typeof(RackSummaryView).FullName);
_regionManager.RequestNavigate(RegionNames.RackContentRegion, typeof(RackSummaryView).FullName);
}
}
RackSummaryViewModel.cs
-> Overview of racks. Go to RackDataView, when click on object
public class RackSummaryViewModel : BindableBase, IRackSummaryViewModel
{
private readonly IRegionManager _regionManager;
private readonly IEventAggregator _eventAggregator;
private readonly IUnityContainer _container;
public DelegateCommand<SearchEventArgs> OnSearch { get; private set; }
public DelegateCommand AdvancedRackSearchCommand { get; private set; }
public InteractionRequest<AdvancedRackSearchNotification> AdvancedSearchRequest { get; private set; }
private ObservableCollection<RackSummaryEntry> _racks;
public ObservableCollection<RackSummaryEntry> Racks
{
get { return _racks; }
private set {SetProperty(ref _racks, value);}
}
private RackSummaryEntry _currentRack;
public RackSummaryEntry CurrentRack
{
get { return _currentRack; }
set
{
if (SetProperty(ref _currentRack, value))
{
if (_currentRack != null)
{
var parameters = new NavigationParameters();
parameters.Add("RackID", _currentRack.PrimaryKey.ToString(GuidNumericFormatSpecifier));
_container.RegisterType<Object, RackDataView>(typeof(RackDataView).FullName);
_regionManager.RequestNavigate(RegionNames.RackContentRegion, new Uri(typeof(RackDataView).FullName + parameters, UriKind.Relative));
}
}
}
}
private const string GuidNumericFormatSpecifier = "N";
public RackSummaryViewModel(IEventAggregator eventAggregator, IRegionManager regionManager, IUnityContainer container)
{
_regionManager = regionManager;
_eventAggregator = eventAggregator;
_container = container;
ISessionFactory factory = new SessionFactory();
container.RegisterType<IRepository, Repository>(new InjectionConstructor(factory.CurrentUoW));
IUnitOfWork unitOfWork = factory.CurrentUoW;
IRepository localrepository = new Repository(unitOfWork);
var query = localrepository.GetList<DMS.Domain.Domain.Rack>();
Racks = new ObservableCollection<RackSummaryEntry>(query
.Select(x => new RackSummaryEntry
{
PrimaryKey = x.PrimaryKey,
Country = x.Location.Address.Country,
City = x.Location.Address.City,
Street = x.Location.Address.Street,
Building = x.Location.BuildingName,
RoomName = x.Location.RoomName,
RackName = x.RackName,
RackHeight = x.RackHeight
}).ToList());
}
}
RackDataViewModel.cs
-> Only Button "Save" und "Go Back"
public class RackDataViewModel : BindableBase, IRackDataViewModel, INavigationAware, IRegionMemberLifetime
{
private IRegionNavigationJournal _navigationJournal;
private readonly IRegionManager _regionManager;
private readonly IUnityContainer _container;
private readonly IEventAggregator _eventAggregator;
public DelegateCommand GoBackCommand { get; private set; }
public DelegateCommand SaveCommand { get; private set; }
public InteractionRequest<INotification> SaveNotificationRequest { get; private set; }
private const string RackIdKey = "RackID";
private const string EType = "EditType";
private const string GuidNumericFormatSpecifier = "N";
public DMS.Domain.Domain.Rack rack;
// [InjectionConstructor] check if necessary
public RackDataViewModel(IRegionManager regionManager, IRegionNavigationJournal navigationJournal, IUnityContainer container, IEventAggregator eventAggregator, ILoggerFactory logFactory)
{
_regionManager = regionManager;
_navigationJournal = navigationJournal;
_container = container;
_eventAggregator = eventAggregator;
GoBackCommand = new DelegateCommand(OnGoBackExecute);
SaveCommand = new DelegateCommand(OnSaveExecute);
SaveNotificationRequest = new InteractionRequest<INotification>();
}
private void OnGoBackExecute()
{
if (_navigationJournal != null)
{
while (_navigationJournal.CanGoBack)
_navigationJournal.GoBack();
_regionManager.Regions.Remove(RegionNames.RackGeneralDataRegion);
}
}
private void OnSaveExecute()
{
SaveNotificationRequest.Raise(new Notification { Content = "Save changes submitted", Title = "Save changes" });
}
public bool KeepAlive
{
get { return false; }
}
private Guid? GetRequestedRackId(NavigationContext navigationContext)
{
var rack = navigationContext.Parameters[RackIdKey];
Guid rackId;
if (rack != null)
{
if (rack is Guid)
rackId = (Guid)rack;
else
rackId = Guid.Parse(rack.ToString());
return rackId;
}
return null;
}
bool INavigationAware.IsNavigationTarget(NavigationContext navigationContext)
{
var type = navigationContext.Parameters[EType];
if (rack == null || ((string)type) == "New")
return true;
var requestedRackId = GetRequestedRackId(navigationContext);
return requestedRackId.HasValue && requestedRackId.Value == rack.PrimaryKey;
}
void INavigationAware.OnNavigatedFrom(NavigationContext navigationContext)
{
}
void INavigationAware.OnNavigatedTo(NavigationContext navigationContext)
{
Guid? rackId;
NavigationParameters parameters = new NavigationParameters();
string key = navigationContext.Parameters[RackIdKey].ToString();
rackId = GetRequestedRackId(navigationContext);
parameters = navigationContext.Parameters;
_regionManager.RequestNavigate(RegionNames.RackGeneralDataRegion, new Uri(typeof(GeneralDataView).FullName + parameters, UriKind.Relative));
_navigationJournal = navigationContext.NavigationService.Journal;
}
}
GeneralDataViewModel.cs
-> Is in region of RackDataView with the data of the racks
public class GeneralDataViewModel : BindableBase, IGeneralDataViewModel, INavigationAware
{
private IRegionNavigationJournal _navigationJournal;
private readonly IRegionManager _regionManager;
private readonly IRepository _repository;
private const string RackIdKey = "RackID";
public DMS.Domain.Domain.Rack Rack { get; set; }
public List<Location> Locations { get; set; }
public GeneralDataViewModel(IRegionManager regionManager, IRepository repository)
{
_regionManager = regionManager;
_repository = repository;
}
private Guid? GetRequestedRackId(NavigationContext navigationContext)
{
var rack = navigationContext.Parameters[RackIdKey];
Guid rackId;
if (rack != null)
{
if (rack is Guid)
rackId = (Guid)rack;
else
rackId = Guid.Parse(rack.ToString());
return rackId;
}
return null;
}
bool INavigationAware.IsNavigationTarget(NavigationContext navigationContext)
{
if (Rack == null)
return true;
var requestedRackId = GetRequestedRackId(navigationContext);
return requestedRackId.HasValue && requestedRackId.Value == Rack.PrimaryKey;
}
void INavigationAware.OnNavigatedFrom(NavigationContext navigationContext)
{
// Intentionally not implemented.
}
void INavigationAware.OnNavigatedTo(NavigationContext navigationContext)
{
var rackId = GetRequestedRackId(navigationContext);
Rack = _repository.GetEntity<DMS.Domain.Domain.Rack>(rackId);
_navigationJournal = navigationContext.NavigationService.Journal;
}
}

Resources