How To Reduce Queries On Layout .NET Core - database

I created a class for getting my settings of website. In this settings table I'm storing phone number, email adress, address etc. Admin user can change their settings.
public interface IAppGlobalVariableService
{
Task<List<Configuration>> GetAllConfig();
Task<string> GetValue(string name);
}
public class AppGlobalVariablesService : IAppGlobalVariableService
{
private readonly IRepository<Configuration> _configRepository;
private static Task<List<Configuration>> _configList;
public AppGlobalVariablesService(IRepository<Configuration> configRepository)
{
_configRepository = configRepository;
_configList = GetAllConfig();
}
public async Task<List<Configuration>> GetAllConfig()
{
return await _configRepository.GetAll().ToListAsync();
}
public Task<string> GetValue(string name)
{
return GetConfigByName(name);
}
private static async Task<string> GetConfigByName(string name)
{
var configList = await _configList;
return configList.FirstOrDefault(x => x.ConfigName == name)?.ConfigValue;
}
}
In layout, I'm calling my settings like view components style.
#await AppConfig.GetValue("Facebook")
I injected _ViewImports
#inject IAppGlobalVariableService AppConfig
I will use this code most of place. Do you have any idea to reduce queries for dotnet core 2.2 ? Can I do something like querying database once to get variables. And store cache ?
UPDATE:
I updated my startup.cs file (AddTransient to AddScoped) It redureced queries. But I want to learn can I use single query ?
services.AddScoped<IAppGlobalVariableService, AppGlobalVariablesService>();

Related

ABPFramwork - Remove api from layer application in swagger

I have created a project using abpframwork. When running swagger, swagger receives the function in the application layer is a api. I don't want that. Can you guys tell me how to remove it in swagger
Code in Application Layer
public class UserService : AdminSSOAppService, ITransientDependency, IValidationEnabled, IUserService
{
IUserRepository _userRepository;
private readonly ILogger<UserService> _log;
public UserService(IUserRepository userRepository,
ILogger<UserService> log
)
{
_userRepository = userRepository;
_log = log;
}
public async Task<List<UserDto>> GetList()
{
var list = await _userRepository.GetListAsync();
return ObjectMapper.Map<List<User>, List<UserDto>>(list);
}
public async Task<UserDto> GetUserById(int Id)
{
var user = await _userRepository.GetAsync(c=>c.Id == Id);
return ObjectMapper.Map<User, UserDto>(user);
}
}
Code in HttpApi Layer
[Area(AdminSSORemoteServiceConsts.ModuleName)]
[RemoteService(Name = AdminSSORemoteServiceConsts.RemoteServiceName)]
[Route("api/user/user-profile")]
public class UserController : ControllerBase, IUserService
{
private readonly IUserService _userAppService;
public UserController(IUserService userAppService)
{
_userAppService = userAppService;
}
[HttpGet]
[Route("get-list-httpapi")]
public Task<List<UserDto>> GetList()
{
return _userAppService.GetList();
}
[HttpGet]
[Route("get-by-id-httpapi")]
public Task<UserDto> GetUserById(int Id)
{
return _userAppService.GetUserById(Id);
}
}
I can suggest a workaround as to enable only the APIs you need to appear on swagger (though the ones that don't appear anymore will still be available for consumption).
I would suggest you add a configuration part in your *.Http.Api project module inside your ConfigureSwaggerServices, like so:
context.Services.AddSwaggerGen(options =>
{
options.DocInclusionPredicate(
(_, apiDesc) =>
apiDesc
.CustomAttributes()
.OfType<IncludeInSwaggerDocAttribute>()
.Any());
});
And for the attribute, it would be very simple, like so:
[AttributeUsage(AttributeTargets.Class)]
public class IncludeInSwaggerDocAttribute : Attribute
{
}
This will let you achieve what you want, however I still recommend reading the doc carefully to be able to implement DDD.

Is there any way that could help me select specific data from table in Microsoft.AspNetCore.Datasync.EFCore

Am learning about data sync from API to WPF app. Got a demo from https://github.com/Azure/azure-mobile-apps/tree/main/samples. But I got into a problem that all the data inside the tables are collected on the call but I need to select specific data using Id. Tried a query etc all came to nothing. Please guide me
Thank you
PatientsController.cs
[Route("tables/Patients")]
public class PatientsController : TableController<Patients>
{
public PatientsController(AppDbContext context)
: base(new EntityTableRepository<Patients>(context))
{
}
}
AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Patients> Patients => Set<Patients>();
}
Try to use the following code:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Patients> Patients {get;set;}
}
controller:
[Route("tables/Patients")]
public class PatientsController : TableController<Patients>
{
private readonly AppDbContext _context;
public PatientsController(AppDbContext context)
: base(new EntityTableRepository<Patients>(context))
{
_context=context;
}
public async Task<IActionResult> Index(int id){
var Patients=_context.Patients.FindAsync(id);
return View(Patients);
}
}
If you just need to get a record by Id, you use the URL https://mysite/tables/myTable/id - no search required - it will go directly to the entity you want.
If you need to limit what a user can see, you will need to implement an access control provider (which is an implementation of IAccessControlProvider). This provides three methods to limit what a user can see and do model updates for ensuring the write operations store the right thing. You can read more here: https://learn.microsoft.com/en-us/azure/developer/mobile-apps/azure-mobile-apps/howto/server/dotnet-core#configure-access-permissions
If it's something else, you'll need to be a little more specific. I hang out in the issues and discussions of the azure/azure-mobile-apps repo, so feel free to file a question there.

How can I access HttpContext Header values in Static class

I am programming an ASP.NET Core 5.0 Web API.
I have a CurrentUser class like this. I want to access the header info anywhere in the project by using CurrentUser.Id. How can I do that? (or where can I initialize httpContext variable?)
public class CurrentUser
{
private static HttpContext _context;
private static UserDto _myUserObj;
public static void Initialize(AuthorizationFilterContext context)
{
_context = context.HttpContext;
_myUserObj = context.HttpContext.Request.Headers["User"] as UserDto;
}
public static int Id()
{
return _myUserObj.Id
}
}
I found some solutions. But I think its not best practice solutions. (There must be another and better way..)
MySolutions is that:
I am building a custom Attribute and i am adding it every API Controller like this:
[MyCustomAttribute]
public class UserController : ControllerBase{
//blablabla
}
After this : I am setting my CurrentUser.Initilaze() method in this Attribute like this:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyCustomAttribute: Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
//fortest
var userObj = context.HttpContext.Request.Headers["User"];//working
var userObj2 = JsonSerializer.Deserialize<UserDto>(userObj, new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
});//working
CurrentUser.Initialize(context);//working
var testResult = CurrentUser.Test();//working
}
}
So I can use CurrentUser static class everywhere in N-Layerd project and I am accessing UserId or another variables..
But i am saying again, I think its not best solution. Because I have to add [MyCustomAttribute] to all Controllers. There must be a better solition.

How to store user information in one place after login and access in multiple WEB API controllers

I am working on Web API with AngularJS. I had implemented Web API token mechanism few days ago and able to login the application using the access token. I have used external DB table instead of ASP.NET identity table to authorize user.
I want to store user information in class so that it can be accessed easily from different controllers after User logged in. Currently I am using ClaimsIdentity in Controller Class to get the user information.
UserIdentityViewModel.cs
public class UserIdentityViewModel
{
public string UserName { get; set; }
public Guid UserId { get; set; }
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
var myProvider = new AuthorizationServerProvider();
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = myProvider
};
app.UseOAuthAuthorizationServer(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
AuthorizationServerProvider.cs
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated(); //
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
string userId = context.UserName;
string password = context.Password;
EmployeeAccessBLL chkEmpAccessBLL = new EmployeeAccessBLL();
EmployeeAccessViewModel vmEmployeeAccess = chkEmpAccessBLL.CheckEmployeeAccess(Convert.ToInt32(userId), password);
if(vmEmployeeAccess != null)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("username", vmEmployeeAccess.EmpName));
identity.AddClaim(new Claim("userid", Convert.ToString(vmEmployeeAccess.EmployeeId)));
UserIdentityViewModel vmUser = new UserIdentityViewModel();
vmUser.UserId = vmEmployeeAccess.EmployeeId;
vmUser.UserName = vmEmployeeAccess.EmpName;
context.Validated(identity);
}
else
{
context.SetError("invalid_grant", "Provided username and password is incorrect");
return;
}
}
}
EventController.cs
public class StreamEventController : ApiController
{
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
//Able to get User Information from Identity.Claims
var identity = (ClaimsIdentity)User.Identity;
string userId = identity.Claims
.Where(c => c.Type == "userid")
.Select(c => c.Value).FirstOrDefault();
//Not able to get User Information from following as new object instance gets created
UserIdentityViewModel vmUser = new UserIdentityViewModel();
vmEvent.CreatedBy = vmUser.UserId;
vmEvent.ModifiedBy = vmUser.UserId;
}
}
Instead of writing "Identity.Claims" in each method of every controller I want to use simple get/set approach or any other methodology to get User Information . The use of Static class is also bad in my opinion as it will store one information of user and multiple user login information gets missed.
Please help me and share with me the best approach that has been used in other Web API projects for login.
You can add a private variable which will be set in the constructor of the controller, like this:
// Should only be used in protected methods.
private ClaimsIdentity ThisUser = null;
public MyController()
{
if (User.Identity.IsAuthenticated)
ThisUser = (ClaimsIdentity)User.Identity;
}
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
string userId = ThisUser.FindFirstValue("userid");
}
Or create a User class where you load all properties:
private UserClass ThisUser = null;
public MyController()
{
if (User.Identity.IsAuthenticated)
ThisUser = new UserClass(User);
}
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
string userId = ThisUser.UserId;
}
Where UserClass is something like:
public class UserClass
{
public string UserId { get; private set; }
public UserClass(IPrincipal user)
{
UserId = user.FindFirstValue("userid");
}
}
But this is just overhead for the same thing.
You can consider to move things to an extension. In that case you get something like:
public static class RequestExtensions
{
public static UserClass GetUser(this HttpRequestMessage request)
{
return new UserClass(request.GetOwinContext().Authentication.User);
}
public static ClaimsIdentiy GetUser2(this HttpRequestMessage request)
{
return new (ClaimsIdentity)request.GetOwinContext().Authentication.User;
}
}
Which you can call:
[Authorize]
[Route("api/addevent")]
[HttpPost]
public List<string> AddEvent(StreamEventViewModel vmEvent)
{
string userId = Request.GetUser.UserId;
string userId2 = Request.GetUser2.FindFirstValue("userid");
}
I think I would go for Request.GetUser2.FindFirstValue("userid");
The code is meant to give you an idea. I didn't test the code but I think it should work.

asp.net identity authentication for simple registration -- asp.net mvc

I am about to start a project that needs custom identity authetication and authorization.
For authentication I am asking this question.
I need to know how can I create ExampleDBContext class that extends from DBContext class? and what settings I need to do in Startup.Auth.cs to make it work. And for registration, what should be the name of the registration table and what should be its columns? and what other tables and their columns need to be there?
There is so much info related to identity authentication but nothing actually useful. thanks
I'm not sure but I think you want something like this:
ExampleDbContext.cs
public class ExampleDbContext : IdentityDbContext<User>, IExampleDbContext
{
public ExampleDbContext()
: base("yourConnectionStringName", throwIfV1Schema: false)
{
}
public static ExampleDbContext Create()
{
return new ExampleDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<IdentityRole>().ToTable("Roles");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
}
void IDisposable.Dispose()
{
this.Dispose();
}
}
You can use the code first method to generate the tables. That means that you can customize your User model the way you want. Here is the example of
User.cs
public class User : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
In the Users you can see that I've added some custom fields (FirstName LastName) and if you use the code first you can generate the custom Users table and use it for authentication. No need to add anything in Startup.Auth.cs you just need to setup dependency injection correctly.

Resources