How can I access HttpContext Header values in Static class - static

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.

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 To Reduce Queries On Layout .NET Core

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>();

Trying to set up a Dapper-based Data Access Layer. ABP.Dapper documentation is confusing and incomplete

I'm trying to set up a simple DAL that will return a List of typed objects. Pretty standard data repository stuff. I downloaded all of ABP's code from GitHub, built the DLLs for Abp.Dapper and Abp.EntityFrameworkCore and started following the instructions on this page:
https://aspnetboilerplate.com/Pages/Documents/Dapper-Integration
But I can't even get past step one of this. This code doesn't compile because it doesn't know what SampleApplicationModule is. But there's no guidance in these instructions as to what that is supposed to be.
How am I supposed to use Abp's libraries? I'm lost. Can someone please let me know the minimum number of things I need to do in order to wire up my database to Abp's library and query for a List of typed objects?
Code from Abp's Dapper Integration documentation:
[DependsOn(
typeof(AbpEntityFrameworkCoreModule),
typeof(AbpDapperModule)
)]
public class MyModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(SampleApplicationModule).GetAssembly());
}
}
if you are confused what to write for SampleApplicationModule use the below code
Module Registration
[DependsOn(
typeof(AbpEntityFrameworkModule),
typeof(AbpKernelModule),
typeof(AbpDapperModule)
)]
public class SampleApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
Usage
public class SomeDomainService : ITransientDependency
{
private readonly IDapperRepository<Animal> _animalDapperRepository;
private readonly IRepository<Animal> _animalRepository;
private readonly IDapperRepository<Person> _personDapperRepository;
private readonly IRepository<Person> _personRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public SomeDomainService(
IUnitOfWorkManager unitOfWorkManager,
IRepository<Person> personRepository,
IRepository<Animal> animalRepository,
IDapperRepository<Person> personDapperRepository,
IDapperRepository<Animal> animalDapperRepository)
{
_unitOfWorkManager = unitOfWorkManager;
_personRepository = personRepository;
_animalRepository = animalRepository;
_personDapperRepository = personDapperRepository;
_animalDapperRepository = animalDapperRepository;
}
public void DoSomeStuff()
{
using (IUnitOfWorkCompleteHandle uow = _unitOfWorkManager.Begin())
{
_personRepository.Insert(new Person("Oğuzhan"));
_personRepository.Insert(new Person("Bread"));
_animalRepository.Insert(new Animal("Bird"));
_animalRepository.Insert(new Animal("Cat"));
_unitOfWorkManager.Current.SaveChanges();
Animal animal = _animalRepository.FirstOrDefault(x => x.Name == "Bird");
Person person = _personDapperRepository.Get(1);
int personCount = _personDapperRepository.Count(x => x.Name == "Oğuzhan");
List<Animal> persons = _animalDapperRepository.GetList(x => x.Name.StartsWith("O")).ToList();
uow.Complete();
}
}
}
See the related post for AbpDapper
https://github.com/aspnetboilerplate/aspnetboilerplate/pull/1854#issuecomment-284511423
PS: Abp.Dapper integration is implemented by the community.

Instantiate IUnitOfWork for each ViewModels in WPF/Prism app

I have lots of repositories like this:
public class PersonRepository : IPersonRepository
{
private readonly IUnitOfWork _unitOfWork;
public PersonRepository(IUnitOfWork instance)
{
_unitOfWork = instance;
}
//Remove, Get methods...
public void Add(Person p)
{
_unitOfWork.Context.People.Add(p);
}
}
and Unit of work class like this:
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(){ }
private readonly HezarehContext _context = new HezarehContext();
public HezarehContext Context
{
get
{
return _context;
}
}
public int Save()
{
return _context.SaveChanges();
}
public void Initialize()
{
Context.Database.Initialize(false);
}
#region IDisposable Members
public void Dispose()
{
_context.Dispose();
}
#endregion
}
Now i want each time my ViewModels gets resolved, a new IUnitOfWork instantiated. Most of my ViewModels are like this:
public class PeopleMainViewModel : NotificationObject
{
// both of repositories must have same instance of IUnitOfWork
private readonly IPersonRepository _personRepository = ServiceLocator.Current.GetService<IPersonRepository>();
private readonly ICategoryRepository _categoryRepository = ServiceLocator.Current.GetService<ICategoryRepository>();
public PeopleMainViewModel()
{
InitializeView();
}
// add, edit, remove commands ...
}
ViewModels always gets resolved using Unity Container like this:
Container.RegisterType<IPersonRepository, PersonRepository>();
// resolve in InjectionProperty...
Container.RegisterType<Object, PeopleMainView>("PeopleMainView", new InjectionProperty(PeopleMainView.DataContextProperty.Name, Container.Resolve<PeopleMainViewModel>();
And my question is, How and Where i Register my ViewModels and IUnitOfWork to have IUnitOfWork instance for each of them?
If I understand your question, just register your IUnitOfWork the same way (and same place) you register the repository in your above example. You don't need to register your ViewModels based on your current design since you aren't using an Interface.
Container.RegisterType<IUnitOfWork, UnitOfWork>();
And continue to have your repositories accept the IUnitOfWork in the constructor. This will allow Unity to use constructor injection to provide a new instance of IUnitOfWork each time it resolves a repository. By default, you'll get a new instance of the IUnitOfWork each time. If you'd like to have a singleton IUnitOfWork, you would have to say so when you register the IUnitOfWork like this:
Container.RegisterType<IUnitOfWork, UnitOfWork>(new ContainerControlledLifetimeManager());
If you want to read up on Lifetime Managers, you can do so here.
I would also recommend changing your ViewModels to take the repositories in as Constructor Parameters, like this if you are going to Resolve them (so Unity will do the work without you referencing the ServiceLocator directly)
public PeopleMainViewModel(IPersonRepository personRepo, ICategoryRepository categoryRepo)
{
...
}
Update:
There is another solution here in unity.codeplex discussions.
I finally found a solution.
There is a feature in Unity container that let you pass parameters while resolving a Type. by changing constructor of ViewModels to this:
public class PeopleMainViewModel : NotificationObject
{
private readonly IPersonRepository _personRepository = null;
private readonly ICategoryRepository _categoryRepository = null;
public PeopleMainViewModel(IUnityContainer container, IUnitOfWork unitOfWork)
{
// now both of repositories have same instance of IUnitOfWork
_personRepository = container.Resolve<IPersonRepository>(new ParameterOverride("unitOfWork", unitOfWork));
_categoryRepository = container.Resolve<ICategoryRepository>(new ParameterOverride("unitOfWork", unitOfWork));
InitializeView();
}
// add, edit, remove commands ...
}
problem solved. now _personReposiotry and _categoryRepository have reference to same instance of unitOfWork.

Resources