I have a BaseApiController which my controller inherits from. It overrides the Initialize method. The method will retrieve a JWT token from the HttpControllerContext and use it to retrieve the user making the request.
public class BaseApiController : ApiController
{
public static tUser CurrentUser;
public BaseApiController()
{
}
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
var request = controllerContext.Request;
if (request.Headers.Authorization != null && request.Headers.Authorization.Scheme.Equals("bearer", StringComparison.OrdinalIgnoreCase))
{
CurrentUser = Helpers.JwtAuthentication.UserToken(request.Headers.Authorization.Parameter);
}
}
}
The error happens, intermittently, when calling the UserToken method. Here is the method.
public static tUser UserToken(string token)
{
string username = ExtractUserName(token);
if (string.IsNullOrEmpty(username))
return null;
try
{
tUser user = Repository.DB.tUsers.Where(u => u.UserName == username && u.IsDeleted == false).FirstOrDefault();
return user;
}
catch (Exception ex)
{
return null;
}
}
The exception is thrown on the line tUser user = Repository.DB.tUsers.Where(u => u.UserName == username && u.IsDeleted == false).FirstOrDefault(); and I can't tell why. If I examine the various objects in the line of code they aren't null. If I execute the debugger over the line of code again it runs with no problems.
Why does this line of code intermittently throw error 'Object reference is not sent to an instance of an object'?
public class Repository
{
public static Entities DB = new Entities(ConfigurationManager.AppSettings["ConnectionString"].ToString());
}
public partial class Entities : DbContext
{
public Entities(string secret) : base(Helpers.KeyVault.GetSecret(secret))
{
this.Configuration.LazyLoadingEnabled = false;
}
}
As stated in comments, to ease search for others with similar issues:
"New up" dbContext directly in BaseApiController in using clock or with using statement (using var ctx = new Entities(string secret)) - this will do the trick.
Alternative would be to force Repository to always return new instance of dbContext by replaceing
public static Entities DB = new Entities(ConfigurationManager.AppSettings["ConnectionString"].ToString());
with a property
public static Entities DB => new Entities(ConfigurationManager.AppSettings["ConnectionString"].ToString());
It should resolve possible scope issue and do the trick if there is no problem with actually resolving custom dbContext class.
Related
I have a c# project with EF and repository pattern.
For single database everything work's fine but I have different model which are related to different database like User model data are come from control panel database and other model are also come from different database.
Here I use common repository pattern for the project. Now how can I send the database connection string to the repository when I initialize the model?
Here is my repository pattern :
public class Repository<C,T> : IRepository<T> where T : class where C : DbContext, new()
{
private C _context = new C();
public C context
{
get
{
//if (_context == null)
//{
// _context = new C();
// _context.Database.Connection.ConnectionString = "the new connectionstring";
//}
//return dataContext;
return _context;
}
set { _context = value; }
}
private IDbSet<T> _entities;
private IDbSet<T> Entities
{
get
{
if (_entities == null)
_entities = context.Set<T>();
return _entities;
}
}
And this is my Service class
public class UserService: Repository<DyeingContext,User> , IUserRepository
{
public UserService()
{
DyeingContext d = new DyeingContext(DataBase.ControlPanal);
}
//private readonly IRepository<User> _useRepository = new Repository<User>(new DyeingContext(DataBase.ControlPanal));
}``
and here is my context class
public partial class DyeingContext:DbContext
{
public DyeingContext(string pDbName):base(GetTheContext(pDbName))
{
}
public DyeingContext():base()
{
//throw new NotImplementedException();
}
public static string GetTheContext(string pDbName)
{
return ConnectionSettings.GetConnectionStringByDbName(pDbName);
}
}
I cant get the connection string in here
DyeingContext d = new DyeingContext(DataBase.ControlPanal);
it says
database connection through exception of type system.argumentexception
Is there a way to pass the multiple connections strings to the repository?
How and where I should initialize my connection string and how I pass it through rerpository?
I am not sure if you received your answer from the above comments. But here is how i would implement that.
1- Create a dbContext concrete class for each database. Both inheriting from EF DbContext.
2- In config file, create a connection string key for each database. This key is then supplied to each dbContext class as ctr param. As follows:
public DB1Context()
: base("db1") // connection string key
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
public DB2Context()
: base("db2") // connection string key
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
3- Each database must have its own repositories. For instance, AccountRepository inherits from the base repository. Its db context is supplied on contructor init as follows.
public class AccountRepository : DataRepositoryBase<Account>, IAccountRepository
{
private DB1Context db1Context = new DB1Context();
public AccountRepository()
{
this.DBContext = db1Context;
}
}
This way, you can communicate with multiple databases through its repositories. The same engine / service can inject repositories from different databases.
public class BaseController : Controller
{
// GET: Base
public static UserManager.User _CurrentUser;
}
}
This code is part of my BaseController and I want to use _CurrrentUser.Id as key for outputcache.
[OutputCache(Duration = 1200, VaryByCustom = _CurrentUser.Id)]
When I tried to do this, it say "Argument in attribute must be constant exprssion" and it's also need to set to static.
I can make this property static but how I can make it constant expression so I can use it for outputcache.
I recommend you should get CurrentUserId from Auth. Cookie. I use like that.
[Authorize]
public class BaseController : Controller
{
private UserModel _currentUser;
public UserModel CurrentUser => _currentUser ?? (_currentUser = GetCurrentUser());
private UserModel GetCurrentUser()
{
UserModel currentUser;
if (!User.Identity.IsAuthenticated) return null;
try
{
var userDataFromCookie = CookieHelper.GetCookie(FormsAuthentication.FormsCookieName);
if (string.IsNullOrWhiteSpace(userDataFromCookie))
throw new ArgumentException("Authentication cookie is null");
currentUser = JsonHelper.Deserialize<UserModel>(FormsAuthentication.Decrypt(userDataFromCookie)?.UserData);
}
catch (Exception)
{
throw;
}
return currentUser;
}
}
Cookie Helper Method like that
public static string GetCookie(string key)
{
return HttpContext.Current.Request.Cookies[key] != null ? HttpContext.Current.Request.Cookies[key].Value : null;
}
source: https://gist.github.com/sniffdk/7600822
The following code is run by an activity outside of an http request, so i need to mock the http context.
I have mocked the http context like so:
public class GetUmbracoServiceMockedHttpContext : IGetUmbracoService
{
private UmbracoHelper umbracoHelper;
public T GetService<T>()
where T : IService
{
UmbracoContext context = UmbracoContext.Current;
if (context == null)
{
var dummyHttpContext = new HttpContextWrapper(new HttpContext(new SimpleWorkerRequest("blah.aspx", "", new StringWriter())));
context = UmbracoContext.EnsureContext(
dummyHttpContext,
ApplicationContext.Current,
new WebSecurity(dummyHttpContext, ApplicationContext.Current),
UmbracoConfig.For.UmbracoSettings(),
UrlProviderResolver.Current.Providers,
false);
}
var serviceTypeProperty = context.Application.Services
.GetType()
.GetProperties()
.SingleOrDefault(x => x.PropertyType == typeof(T));
if (serviceTypeProperty == null)
{
return default(T);
}
return (T)serviceTypeProperty
.GetValue(context.Application.Services);
}
}
I inject this IGetUmbracoService service into a controller and call:
service.GetService<IContentService>().SaveAndPublishWithStatus(item);
... The following error occurs.
System.ArgumentNullException: Value cannot be null. Parameter name:
httpContext at System.Web.HttpContextWrapper..ctor(HttpContext
httpContext) at
Umbraco.Web.SingletonHttpContextAccessor.get_Value() at
Umbraco.Web.RequestLifespanMessagesFactory.Get() at
Umbraco.Core.Services.ContentService.SaveAndPublishDo(IContent
content, Int32 userId, Boolean raiseEvents) at
Umbraco.Core.Services.ContentService.Umbraco.Core.Services.IContentServiceOperations.SaveAndPublish(IContent
content, Int32 userId, Boolean raiseEvents) at
Umbraco.Core.Services.ContentService.SaveAndPublishWithStatus(IContent
content, Int32 userId, Boolean raiseEvents)
How do i mock the http context without using the frowned upon HttpContext.Current = ...?
I assume the relevant issue comes from:
RequestLifespanMessagesFactory.cs
which in turn is calling an implementation of this:
SingletonHttpContextAccessor.cs
I did some work with Umbraco, running it from a console app and then using the Umbraco API to call into Umbraco.
I believe I based it on this project: https://github.com/sitereactor/umbraco-console-example
Might be useful.
Thanks user369142. This is what ended up working:
I also had to make sure that i was not raising any events on the SaveandPublish calls... as the HttpContext expects there to be messages registered in the context but we do not mock any... If you make sure raise events is false, it skips over the code that cares about that.
public class CustomSingletonHttpContextAccessor : IHttpContextAccessor
{
public HttpContextBase Value
{
get
{
HttpContext context = HttpContext.Current;
if (context == null)
{
context = new HttpContext(new HttpRequest(null, "http://mockurl.com", null), new HttpResponse(null));
}
return new HttpContextWrapper(context);
}
}
}
public class CustomRequestLifespanMessagesFactory : IEventMessagesFactory
{
private readonly IHttpContextAccessor _httpAccessor;
public CustomRequestLifespanMessagesFactory(IHttpContextAccessor httpAccessor)
{
if (httpAccessor == null)
{
throw new ArgumentNullException("httpAccessor");
}
_httpAccessor = httpAccessor;
}
public EventMessages Get()
{
if (_httpAccessor.Value.Items[typeof(CustomRequestLifespanMessagesFactory).Name] == null)
{
_httpAccessor.Value.Items[typeof(CustomRequestLifespanMessagesFactory).Name] = new EventMessages();
}
return (EventMessages)_httpAccessor.Value.Items[typeof(CustomRequestLifespanMessagesFactory).Name];
}
}
public class CustomBootManager : WebBootManager
{
public CustomBootManager(UmbracoApplicationBase umbracoApplication)
: base(umbracoApplication)
{
}
protected override ServiceContext CreateServiceContext(DatabaseContext dbContext, IDatabaseFactory dbFactory)
{
//use a request based messaging factory
var evtMsgs = new CustomRequestLifespanMessagesFactory(new CustomSingletonHttpContextAccessor());
return new ServiceContext(
new RepositoryFactory(ApplicationCache, ProfilingLogger.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
new PetaPocoUnitOfWorkProvider(dbFactory),
new FileUnitOfWorkProvider(),
new PublishingStrategy(evtMsgs, ProfilingLogger.Logger),
ApplicationCache,
ProfilingLogger.Logger,
evtMsgs);
}
}
public class CustomUmbracoApplication : Umbraco.Web.UmbracoApplication
{
...
protected override IBootManager GetBootManager()
{
return new CustomBootManager(this);
}
...
}
I am learning repository and unit of work patterns using generics and dependency injection. I have a persistent error that I have been churning on and I am clearly missing something fundamental.
I am getting the following error which whilst I understand that it is looking for a database table column called 'Id'
Because my Entity class inherits from BaseEntity I suspect this is the problem but I don't understand why and what I am best to do to fix it.
public class BaseEntity<T>
{
public T Id { get; set; }
}
Error returned
An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' >occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: An error occurred while executing the command >definition. See the inner exception for details.
Inner exception
{"Invalid column name 'Id'."}
To add some context I am using EF6 MVC5 and AutoFac for the Dependancy injection.
Entity class
(A column 'id' doesn't exist in the database - the key in the database is 'EmrgencyAttendanceId') and the Entity class also sets the key as 'EmrgencyAttendanceId' like so.
[Table("reporting.EDISRecords")]
public class EDISRecord : BaseEntity<int>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int EmergencyAttendanceId { get; set; }
[StringLength(50)]
public string Hospital { get; set; }
[StringLength(20)]
public string URNumber { get; set; }
Controller action
The controller calls the GetRecord method of the EDISRecordService passing a Lambda expression. I use DbFunctions.TruncateTime because the database stores as date time and I only want to search on the date.
public ActionResult Search(string Date, string CaseNumber)
{
if (!string.IsNullOrEmpty(Date) || !string.IsNullOrEmpty(CaseNumber))
{
DateTime dt = DateTime.Parse(Date);
var EmergencyAttendance = _edisRecordService.GetRecord(m => (DbFunctions.TruncateTime(m.ArrivalDateTime) == dt) && (m.RTAIdentifier == CaseNumber));
//for initialising view model
SeperationSummaryViewModel model = new SeperationSummaryViewModel();
//assign values for view model
if (EmergencyAttendance != null)
{
if (EmergencyAttendance.DepartureDestination != null)
{
if (EmergencyAttendance.DepartureDestination.Substring(0, 1) == ".")
{
model.DepartureDestination = EmergencyAttendance.DepartureDestination.Substring(1);
}
else
{
model.DepartureDestination = EmergencyAttendance.DepartureDestination;
}
}
else
{
model.DepartureDestination = "Not recorded by Emergency Department";
}
if (EmergencyAttendance.InpatientAdmissionDiagnosis != null)
{
model.InpatientAdmissionDiagnosis = EmergencyAttendance.InpatientAdmissionDiagnosis;
}
else
{
model.InpatientAdmissionDiagnosis = "Not recorded by Emergency Department";
}
}
//send view model into UI (View)
return PartialView("_SeperationInformationPartialView", model);
}
else
{
if (string.IsNullOrEmpty(Date) || string.IsNullOrEmpty(CaseNumber))
{
return PartialView("Blank");
}
}
return PartialView("Error");
}
Service Class
The service class instantiates a unit of work and calls the repository Get method passing through the Lambda expression.
public class EDISRecordService : IEDISRecordService
{
private readonly IUnitOfWork<DataWarehouseDataManager> _unitOfWork;
public EDISRecordService(IUnitOfWork<DataWarehouseDataManager> unitOfWork)
{
_unitOfWork = unitOfWork;
}
public EDISRecord GetRecord(Expression<Func<EDISRecord, bool>> #where)
{
return _unitOfWork.EDISRecordRepository.Get(#where);
}
}
RepositoryBase class
The repository class inherits from the repository base class which impliments the Get method passing the lambda to 'Expression> #where'
public class RepositoryBase<TEntity> : Disposable, IRepository<TEntity>
where TEntity : class
{
private readonly DbContext _dataContext;
private IDbSet<TEntity> Dbset
{
get { return _dataContext.Set<TEntity>(); }
}
public RepositoryBase(DbContext dbContext)
{
_dataContext = dbContext;
}
public TEntity Get(Expression<Func<TEntity, bool>> #where)
{
return Dbset.Where(where).FirstOrDefault();
}
protected override void DisposeCore()
{
if (_dataContext != null)
_dataContext.Dispose();
}
}
It fails in this method
public TEntity Get(Expression<Func<TEntity, bool>> #where)
{
return Dbset.Where(where).FirstOrDefault(); <<<<<< Fails Here <<<<<
}
I was on the right track and it was because I was inheriting from the Base Entity.
When I re read my problem it became clear.
The solution was to simply not to inherit from base entity class and all is good.
If you have better approach to handle custom Validation please let me know. I don't want service layer for this please.
Read below 5th option what I want.
I have
1 - IUserRepository -> bool IsUserRegistered(string userName);
2 - UserRepository with Method
readonly EFDBContainer _db = new EFDBContainer();
public bool IsUserRegistered(string userName)
{
return _db.Users.Any(d => d.UserName == userName);
}
3 - Ninject --> UserController is DI
public static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserRepository>().To<UserRepositary>();
}
4 - UserController
private readonly IUserRepository _repository;
public ProfileController(IUserRepository repository)
{
_repository = repository;
}
Create Method on Controller
HttpPost]
public ActionResult Create(string confirmButton, User user)
{
if (ModelState.IsValid)
{
try
{
_repository.Create(user); --> This calling Create Method below before this EnsureValid is Called
return //Do Redirection
}
catch (RuleViolationException)
{
this.UpdateModelStateWithViolations(user, ViewData.ModelState);
}
}
return //to View;
}
Create Method from Repository
public void Create(User user)
{
user.EnsureValid(); --> Go to User object and do validation
//Add object to DB
}
5 - What I want:
Here I want DI so that I can call 1st IsUserRegistered interface method on User object
IsUserRegistered below is not working right now. I need a way to use the Interface
public partial class User: IRuleEntity
{
public List<RuleViolation> GetRuleViolations()
{
List<RuleViolation> validationIssues = new List<RuleViolation>();
if (IsUserRegistered(userName))
validationIssues.Add(new RuleViolation("UserName", UserName, "Username already exists. Please enter a different user name."));
return validationIssues;
}
public void EnsureValid()
{
List<RuleViolation> issues = GetRuleViolations();
if (issues.Count != 0)
throw new RuleViolationException("Business Rule Violations", issues);
}
}
Write your own validation attribute and add it to the user name.
See http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/. It explains how to inject dependencies into validators.
See also the sample application that comes with the Ninject MVC extension it has an example of a validator that has a dependency. https://github.com/ninject/ninject.web.mvc