Implementing Unit Of Work in WinForms - c#

I have implemented the Repository pattern in my WinForms Application:
UnitOfWork:
using RCCGSPP.Core;
using RCCGSPP.Persistence.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
namespace RCCGSPP.Persistence
{
//Implements the Logic for Methods in the IUnitOfWork Interface
public class UnitOfWork
{
//Our App contextClassName
private readonly SPPContext _context;
private DbContext dbContext;
//Recieves our App ContextClassName
public UnitOfWork(SPPContext context)
{
//stores our App ContextName in _context
_context = context;
//Then uses the context to initialise both Repositories
Persons = new PersonRepository(_context);
SundayServices = new SundayServiceRepository(_context);
UserPasses = new UserRepository(_context);
NewComers = new NewComerRepository(_context);
}
public UnitOfWork(DbContext dbContext)
{
this.dbContext = dbContext;
}
//properties
public PersonRepository Persons { get; private set; }
public SundayServiceRepository SundayServices { get; private set; }
public UserRepository UserPasses { get; private set; }
public NewComerRepository NewComers { get; private set; }
//Calls the SaveChanges on the Context
public int Complete()
{
return _context.SaveChanges();
}
//Implementation of the Dispose Method to Dispose the Context
public void Dispose()
{
_context.Dispose();
}
}
}
My Form whwere I want to use my UnitOfWork, I have declared it as a readonly property so I have included it in the contructor to initialise it but since by form is load from another at the click of a Button I get "There is no argument given that corresponds to the required formal parameter 'unitOfWork'"
Form Where To Use UNITOFWORK
public partial class Register : MaterialForm
{
private readonly IUnitOfWork _unitOfWork;
string userName;
string psswrd;
string Confirmpsswrd;
public Register(IUnitOfWork unitOfWork)
{
InitializeComponent();
//Set your preferred colors &theme (Material Skin)
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Blue400, Primary.Red900, Primary.Brown900, Accent.LightBlue200, TextShade.BLACK);
//prevent Form from Resizing
Sizable = false;
//UnitOfWork
_unitOfWork = unitOfWork;
}
private void Register_Load(object sender, EventArgs e)
{
}
private void btnSubmit_Click(object sender, EventArgs e)
{
//Get the User email and Password to register in the DB
userName = textEmail.Text;
psswrd = textPassword.Text;
Confirmpsswrd = textConfirmPassword.Text;
//Compare the password
bool conRes = ComparePassword(psswrd, Confirmpsswrd);
if (conRes)
{
//Insert to db using the UnitOfWork
UserPass userToDb = new UserPass
{
UserName = this.userName,
password = this.psswrd,
};
_unitOfWork.UserPasses.Add(userToDb);
//Commit calling complete()
_unitOfWork.Complete();
//FeedBack Registered Sucessfull
LabelErrorPassword.Text = "Successful, Login!";
}
else
{
LabelErrorPassword.BackColor = Color.Red;
LabelErrorPassword.Text = "The Passwords don't match!"; //show in the Label that password are not the same
}
}
/**********Method to compare Password**********************/
public bool ComparePassword(string pss1, string pss2)
{
if (pss1.Equals(pss2))
{
return true;
}
else return false;
}
}
lOADING MY fORM :
private void BtnRegister_Click(object sender, EventArgs e)
{
//lOAD THE rEGISTER fORM,
Register nForm = new Register();
nForm.Show();
}
How can I make use of my UnitOfWork in my WinForm Application.

As #stuartd said, the parameterless contructor for a Form in WinForms is recommended. But of course you can add a constructor with arguments.
public Register()
{
InitializeComponent();
//Set your preferred colors &theme (Material Skin)
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Blue400, Primary.Red900, Primary.Brown900, Accent.LightBlue200, TextShade.BLACK);
//prevent Form from Resizing
Sizable = false;
//UnitOfWork, not initialized here
//_unitOfWork = unitOfWork;
}
public Register(IUnitOfWork unitOfWork) : this() // call default constructor!
{
_unitOfWork = unitOfWork;
}
I strongly recommend to leave all the auto-generated and custom initialization code in the default (parameterless) constructor. So, the WinForms designer does not stop working.
We use this strategy in combination with DI containers in several projects without any problem.

Thank You all.
I have used the Simple Ijector package to Inject the UnitOfWork into my Program.cs as Follow:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
//Get instance of my Registered HomeForm
Application.Run((container.GetInstance<Home>()));
}
private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
// Register my types, for instance:
container.Register<UnitOfWork, UnitOfWork>();
//Register my HomeForm
container.Register<Home>();
// Optionally verify the container.
//container.Verify();
}
}
Then in my Principal Form: I injected the registered UnitOfWork in it's constructor:
//Declare my UnitOfwORK
private readonly UnitOfWork _unitOfWork;
public Home(UnitOfWork unitOfWork)
{
InitializeComponent();
this._unitOfWork = unitOfWork;
}
Then I pass it to the New Register Form that will be loaded at the click of the Register Button, inside of which I will use the UnitOfWork to persist and commit to the DB
//lOAD THE rEGISTER fORM,
Register nForm = new Register(this._unitOfWork);
nForm.Show();
}
Finally in the Register I use this UnitOfWork to perform my CRUD Operations and Commit to the DB:
public partial class Register : MaterialForm
{
//Declare my UnitOfwORK
private readonly UnitOfWork _unitOfWork;
string userName;
string psswrd;
string Confirmpsswrd;
//I Inject IUnitOfOfClass with the Help of Simple Injector dependency injection library
public Register(UnitOfWork unitOfWork)
{
InitializeComponent();
//Set your preferred colors &theme (Material Skin)
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Blue400, Primary.Red900, Primary.Brown900, Accent.LightBlue200, TextShade.BLACK);
//prevent Form from Resizing
Sizable = false;
_unitOfWork = unitOfWork;
}
private void SetUnitOfWork()
{
}
private void Register_Load(object sender, EventArgs e)
{
}
private void btnSubmit_Click(object sender, EventArgs e)
{
//Get the User email and Password to register in the DB
userName = textEmail.Text;
psswrd = textPassword.Text;
Confirmpsswrd = textConfirmPassword.Text;
//Compare the password
bool conRes = ComparePassword(psswrd, Confirmpsswrd);
if (conRes)
{
//Insert to db using the UnitOfWork
UserPass userToDb = new UserPass
{
UserName = this.userName,
password = this.psswrd,
LastAcess = DateTime.Now
};
_unitOfWork.UserPasses.Add(userToDb);
//Commit calling complete()
_unitOfWork.Complete();
//FeedBack Registered Sucessfull
LabelErrorPassword.Text = "Successful, Login!";
}
else
{
LabelErrorPassword.BackColor = Color.Red;
LabelErrorPassword.Text = "The Passwords don't match!"; //show in the Label that password are not the same
}
}
/**********Method to compare Password**********************/
public bool ComparePassword(string pss1, string pss2)
{
if (pss1.Equals(pss2))
{
return true;
}
else return false;
}
}
It might not be the best way to implement it but It works absolutely fine, I have tested it and I could see the data in the database.

Related

How to instantiate a new Windows Form with Quartz.NET without problems?

I'm using the Quartz.NET library to create a job in my C# application.
I have some registers in my database, so I have a table wich contains a column called "start_date". The job runs every 50 seconds, so I compare the dates from the column "start_date" with the date of my computer, and if the dates are equal, I want to instantiate a new Windows Form with a message and a button.
At the moment, the new Windows Form is opening at the right moment, but the message is not showed and the window stops to respond.
Basically, in my code I have something like this:
FormMessage.cs
public partial class FormMessage : Form
{
public FormMessage()
{
InitializeComponent();
}
public FormMessage(double minutes)
{
InitializeComponent();
string message = string.Format("You have {0} minutes!", minutes);
lblMessage.Text = message ;
}
private void btnOK_Click(object sender, EventArgs e)
{
this.Close();
}
}
JobMessage.cs
public class JobMessage: IJob
{
List<Information> informations;
public void Execute(IJobExecutionContext context)
{
//Class with methods to get registers from database.
InformationAPI infoAPI = new InformationAPI();
informations = infoAPI.GetInformations();
foreach (Information info in informations)
{
DateTime computerDateTime = DateTime.Now;
DateTime infoDateTime = info.StartDate;
double difference;
if (DateTime.Compare(computerDateTime, infoDateTime) < 0)
{
difference = Math.Round(infoDateTime.Subtract(computerDateTime).TotalMinutes);
if (difference == 5)
{
FormMessage formMessage = new FormMessage(difference);
formMessage.Show();
}
}
}
}
}
Someone have some idea of the reason why the FormMessage window stops to respond?
Thank you for your attention!
You can try Quartz Listeners to let them open the form to show the data and keep the execution out of the job scope:
Action<IJobExecutionContext, JobExecutionException> listenerAction = (c, e) => {
var dataMap = context.GetJobDetail().GetJobDataMap();
var difference = dataMap.GetIntValue("difference");
FormMessage formMessage = new FormMessage(difference);
formMessage.Show();
}
var listener = new SyncJobListener(listenerAction);
And add the listener in to the scheduler:
scheduler.ListenerManager.AddJobListener(listener,
GroupMatcher<JobKey>.GroupEquals("GroupName"));
Using this SyncJobListener:
public class SyncJobListener : IJobListener
{
private readonly Action<IJobExecutionContext, JobExecutionException> _syncExecuted;
public string Name { get; private set; }
public SyncJobListener(
Action<IJobExecutionContext, JobExecutionException> syncExecuted
)
{
Name = Guid.NewGuid().ToString();
_syncExecuted = syncExecuted;
}
public void JobToBeExecuted(IJobExecutionContext context)
{
}
public void JobExecutionVetoed(IJobExecutionContext context)
{
}
public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
{
_syncExecuted(context, jobException);
}
}
I have not tested this so if the dataMap does not have any data, you are going to need to allow the persistance:
[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
public class JobMessage: IJob {}

UoW and DbContext fail in an event

I have implemented this Windows Service which sends emails using SendAsync method, every 30 seconds in batches of 20. I'm using EF6 and SQL Server 2016. Here is some parts of the codes
EmailRepository.cs
public class EmailRepository : IEmailRepository
{
private BBEntities db = null;
public EmailRepository(BBEntities db)
{
this.db = db;
}
public IEnumerable<tb_Email> SelectAll(int batchAge, int batchSize)
{
DateTime tDate = DateTime.Now.AddMinutes(batchAge);
return db.tb_Email.Where(x => x.ReadyToSend.Equals(true) & x.DateSent.Equals(null) & x.DateCreated >= tDate).OrderBy(x => x.DateCreated).Take(batchSize);
}
public tb_Email SelectByID(Guid id)
{
return db.tb_Email.Find(id);
}
public void Update(tb_Email obj)
{
db.Entry(obj).State = EntityState.Modified;
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
db.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
UnitOfWork.cs
public class UnitOfWork : IUnitOfWork
{
private readonly BBEntities ctx = new BBEntities();
private IEmailRepository emailRepository;
public IEmailRepository EmailRepository
{
get
{
if (this.emailRepository == null)
{
this.emailRepository = new EmailRepository(ctx);
}
return emailRepository;
}
}
public void Dispose()
{
this.ctx.Dispose();
}
public void Commit()
{
this.ctx.SaveChanges();
}
}
EmailService.cs
public class EmailService : IEmailService
{
private IUnitOfWork unitOfWork;
public EmailService()
{
unitOfWork = new UnitOfWork();
}
public List<tb_Email> SelectAll(int batchAge, int batchSize)
{
return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList();
}
public tb_Email SelectByID(Guid id)
{
return unitOfWork.EmailRepository.SelectByID(id);
}
public void Update(tb_Email obj)
{
using (unitOfWork = new UnitOfWork())
{
unitOfWork.EmailRepository.Update(obj);
unitOfWork.Commit();
}
}
}
SMTPService.cs
public class SMTPService : ISMTPService
{
SmtpClient client;
MailMessage newMessage;
EmailService emailService;
IEventLoggerService MailCheckerLog;
public SMTPService()
{
emailService = new EmailService();
MailCheckerLog = new EventLoggerService();
}
public void SendEmail(tb_Email email)
{
try
{// rest of the code .....
newMessage = new MailMessage();
newMessage.Headers.Add("X-Email_Id", email.Id.ToString());
client.SendCompleted += (sender, e) => SendCompletedCallback(sender, e);
tb_Email userState = email;
//
// if I put the update database logic here, it works fine
//
client.SendAsync(newMessage, userState);
}
catch (Exception e)
{
MailCheckerLog.log("Error in SendComplete event handler - Exception: " + e.Message.ToString() + " -- InnerException: " + e.InnerException.Message, EventLogEntryType.Error);
client.Dispose();
newMessage.Dispose();
throw;
}
}
void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
tb_Email email = (tb_Email)e.UserState;
Console.WriteLine("----------------------------------" + emailID.Id);
email.ReadyToSend = false;
emailService.Update(email);
client.Dispose();
newMessage.Dispose();
}
}
The problem:
So to send and process emails I run SendEmail method in a simple loop with a list of tb_Email objects, once each email is sent I have to update the database.
To do that, I use
email.ReadyToSend = false;
emailService.Update(email);
in my SendCompleted event, as I'm using SendAsync the system goes ahead and process many emails however the SendCompleted event might fire a bit later for each email.
To make sure it is using a unique and single dbContext I am using a using statement on my UoW instance for the update method. This works fine if I put my update logic in SendEmail method directly (which doesn't make any sense as I need to know if the email was sent successfully or not), however If I put it in the event after a few successful updates, it just throw
System.Data.Entity.Core.EntityException: 'The underlying provider failed on Open.'
I don't understand how is it possible when I'm actually creating a new context for each operation.
Sorry I have to answer it myself, the problem was that the UoW variable was still being used by other threads, so the solution is to declare a new variable for the using statement inside the update method, like below
public class EmailService : IEmailService
{
private IUnitOfWork unitOfWork;
public EmailService()
{
unitOfWork = new UnitOfWork();
}
public List<tb_Email> SelectAll(int batchAge, int batchSize)
{
return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList();
}
public tb_Email SelectByID(Guid id)
{
return unitOfWork.EmailRepository.SelectByID(id);
}
public void Update(tb_Email obj)
{
IUnitOfWork unitOfWorkUpdate;
using (unitOfWorkUpdate = new UnitOfWork())
{
unitOfWorkUpdate.EmailRepository.Update(obj);
unitOfWorkUpdate.Commit();
}
}
}

Seemann's Dependency Injection, "Three Calls Pattern" vs Service Locator Anit-Pattern

I have created a WinForms MVC application using Dependency Injection (DI) and Ninject as the DI Container. The basic architecture is as follows
Program.cs (the main entry point of the WinForms application):
static class Program
{
[STAThread]
static void Main()
{
...
CompositionRoot.Initialize(new DependencyModule());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CompositionRoot.Resolve<ApplicationShellView>());
}
}
DependencyModule.cs
public class DependencyModule : NinjectModule
{
public override void Load()
{
Bind<IApplicationShellView>().To<ApplicationShellView>();
Bind<IDocumentController>().To<SpreadsheetController>();
Bind<ISpreadsheetView>().To<SpreadsheetView>();
}
}
CompositionRoot.cs
public class CompositionRoot
{
private static IKernel ninjectKernel;
public static void Initialize(INinjectModule module)
{
ninjectKernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return ninjectKernel.Get<T>();
}
public static IEnumerable<T> ResolveAll<T>()
{
return ninjectKernel.GetAll<T>();
}
}
ApplicationShellView.cs (the main form of the application)
public partial class ApplicationShellView : C1RibbonForm, IApplicationShellView
{
private ApplicationShellController controller;
public ApplicationShellView()
{
this.controller = new ApplicationShellController(this);
InitializeComponent();
}
public void InitializeView()
{
dockPanel.Extender.FloatWindowFactory = new CustomFloatWindowFactory();
dockPanel.Theme = vS2012LightTheme;
}
private void ribbonButtonTest_Click(object sender, EventArgs e)
{
controller.OpenNewSpreadsheet();
}
public DockPanel DockPanel
{
get { return dockPanel; }
}
}
where
public interface IApplicationShellView
{
void InitializeView();
DockPanel DockPanel { get; }
}
ApplicationShellController.cs
public class ApplicationShellController
{
private IApplicationShellView shellView;
public ApplicationShellController(IApplicationShellView view)
{
this.shellView = view;
}
public void OpenNewSpreadsheet(DockState dockState = DockState.Document)
{
SpreadsheetController controller = (SpreadsheetController)GetDocumentController("new.xlsx");
SpreadsheetView view = (SpreadsheetView)controller.New("new.xlsx");
view.Show(shellView.DockPanel, dockState);
}
private IDocumentController GetDocumentController(string path)
{
return CompositionRoot.ResolveAll<IDocumentController>()
.SingleOrDefault(provider => provider.Handles(path));
}
public IApplicationShellView ShellView { get { return shellView; } }
}
SpreadsheetController.cs
public class SpreadsheetController : IDocumentController
{
private ISpreadsheetView view;
public SpreadsheetController(ISpreadsheetView view)
{
this.view = view;
this.view.SetController(this);
}
public bool Handles(string path)
{
string extension = Path.GetExtension(path);
if (!String.IsNullOrEmpty(extension))
{
if (FileTypes.Any(ft => ft.FileExtension.CompareNoCase(extension)))
return true;
}
return false;
}
public void SetViewActive(bool isActive)
{
((SpreadsheetView)view).ShowIcon = isActive;
}
public IDocumentView New(string fileName)
{
// Opens a new file correctly.
}
public IDocumentView Open(string path)
{
// Opens an Excel file correctly.
}
public IEnumerable<DocumentFileType> FileTypes
{
get
{
return new List<DocumentFileType>()
{
new DocumentFileType("CSV", ".csv" ),
new DocumentFileType("Excel", ".xls"),
new DocumentFileType("Excel10", ".xlsx")
};
}
}
}
where the implemented interface is
public interface IDocumentController
{
bool Handles(string path);
void SetViewActive(bool isActive);
IDocumentView New(string fileName);
IDocumentView Open(string path);
IEnumerable<DocumentFileType> FileTypes { get; }
}
Now the view ascociated with this controller is
public partial class SpreadsheetView : DockContent, ISpreadsheetView
{
private IDocumentController controller;
public SpreadsheetView()
{
InitializeComponent();
}
private void SpreadsheetView_Activated(object sender, EventArgs e)
{
controller.SetViewActive(true);
}
private void SpreadsheetView_Deactivate(object sender, EventArgs e)
{
controller.SetViewActive(false);
}
public void SetController(IDocumentController controller)
{
this.controller = controller;
Log.Trace("SpreadsheetView.SetController(): Controller set successfully");
}
public string DisplayName
{
get { return Text; }
set { Text = value; }
}
public WorkbookView WorkbookView
{
get { return workbookView; }
set { workbookView = value; }
}
...
}
Finally the view interfaces are
public interface ISpreadsheetView : IDocumentView
{
WorkbookView WorkbookView { get; set; }
}
and
public interface IDocumentView
{
void SetController(IDocumentController controller);
string DisplayName { get; set; }
bool StatusBarVisible { get; set; }
}
Now for my questions. In Seemann's book "Dependency Injection in .NET" he talks about the "Three Calls Pattern" and this is what I have attempted to implement in the above. The code works, the shell view displays and via the MVC pattern my controllers correctly open views etc. However, I am confused as the above definately has the flavour of the "Service Locator Anti-Pattern". In chapter 3 of Seemann's book he states
The COMPOSITION ROOT pattern describes where you should use a DI CONTAINER. However,
it doesn’t state how to use it. The REGISTER RESOLVE RELEASE pattern addresses
this question [...] A DI CONTAINER should be used in three successive
phases called Register, Resolve, and Release.
In its pure form, the REGISTER RESOLVE RELEASE pattern states that you should only
make a single method call in each phase. Krzysztof Kozimic calls this the Three Calls Pattern.
Configuring a DI CONTAINER in a single method call requires more explanation. The
reason that registration of components should happen in a single method call is
because you should regard configuration of a DI CONTAINER as a single, atomic action.
Once configuration is completed, the container should be regarded as read-only.
This sounds like the dredded "Service locator", why is this not deemed service location?
In order to adjust my code to instead use Contstructor Injection, I changed my entry code to
[STAThread]
static void Main()
{
var kernel = new StandardKernel();
kernel.Bind(t => t.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces());
FileLogHandler fileLogHandler = new FileLogHandler(Utils.GetLogFilePath());
Log.LogHandler = fileLogHandler;
Log.Trace("Program.Main(): Logging initialized");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(kernel.Get<ApplicationShellView>());
}
using Ninject.Extensions.Conventions, I then changed ApplicationShellController in order to correct my code to inject the IDocumentControllers via ctor injection:
public class ApplicationShellController
{
private IApplicationShellView shellView;
private IEnumerable<IDocumentController> controllers;
public ApplicationShellController(IApplicationShellView shellView, IEnumerable<IDocumentController> controllers)
{
this.shellView = shellView;
this.controllers = controllers;
Log.Trace("ApplicationShellController.Ctor(): Shell initialized successfully");
}
...
}
where
public class SpreadsheetController : IDocumentController
{
private ISpreadsheetView view;
public SpreadsheetController(ISpreadsheetView view)
{
this.view = view;
this.view.SetController(this);
}
...
}
but this leads to a circular dependency, how do I handle this?
Question Summary:
Why is my initial use of Ninject using "Thee Calls Pattern" and CompositionRoot.Resolve<T>() bad or different to the Service Locator Anti-Pattern?
How can I resolve the circular dependency issue above if I want to switch to pure ctor injection?
Thanks very much for your time.
At some point in the process, you have to use service location. However, the difference between DI and SL is that in SL, you are resolving your services at the point they are requested, whereas in DI you resolve them in some kind of factory (such as a controller factory) and then construct your objects and pass the reference in.
You should create some kind of infrastructure that dispatches your commands and uses a factory of some kind to locate the dependencies used by the created objects.
In this way, the rest of your code doesn't have dependency resolution, and you are following a DI pattern except at the construction point.

Binding custom IPrincipal and IIdentity with Ninject

I am trying to bind the IIdentity from HttpContext.Current.User.Identity to a custom IPrincipal but from what I can gather, IIdentity is null before user is authenticated.
Sample code:
public interface ICustomPrincipal
{
int UserID { get; set; }
}
public class CustomPrincipal : ICustomPrincipal
{
private readonly IIdentity _identity;
private readonly IUserRepository _userRepository;
public CustomPrincipal(IIdentity identity, IUserRepository repository)
{
_identity = identity;
_repository = repository;
}
}
And then
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (Request.IsAuthenticated && !Request.Url.AbsoluteUri.Contains(".axd"))
{
HttpContext.Current.User as CustomPrincipal;
}
}
I can bind IUserRepository no problem but I do not know how to properly bind IIdentity.
I have tried to bind the HttpContext.Current.User.Identity in CreateKernel() on Application_Start, but the problem is, the IIdentity is null.
I have also tried using GlobalFilters and Ninject.BindFilter method to set the CustomPrincipal but the problem revolves back to IIdentity being null.
I do not want to call the constructor of CustomPrincipal because IUserRepository also involves constructor injection.
I'm unsure of whether I am not binding correctly, or my implementation method is not right, any ideas or suggestions would be appreciated.
What I am trying to achieve in the end is to pass ICustomPrincipal down to the DB level to record the UserID on transactions.
Thanks
here is a sample showing bootstrap AFTER and BEFORE authentication
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//WebApiConfig.Register(GlobalConfiguration.Configuration);
//BundleMobileConfig.RegisterBundles(BundleTable.Bundles);
}
private bool _isBootStrapped;
private bool _isBootStrappedAuthenticated;
public override void Init()
{
base.Init();
// handlers managed by ASP.Net during Forms authentication
BeginRequest += new EventHandler(BeginRequestHandler);
PostAuthorizeRequest += new EventHandler(PostAuthHandler);
EndRequest += new EventHandler(EndRequestHandler);
}
public void EndRequestHandler(object sender, EventArgs e)
{
}
public void BeginRequestHandler(object sender, EventArgs e)
{
BootStrapUnauthentiated();
}
public void PostAuthHandler(object sender, EventArgs e)
{
if (_isBootStrappedAuthenticated)
{
return; // nuff done...
}
BootStrapAuthenticated();
BootStrapUnauthentiated();
}
private void BootStrapAuthenticated()
{
if (Request.IsAuthenticated)
{
BootStrapHttp(Context);
BootStrapper.RegisterInfrastureAdapters();
_isBootStrapped = true;
_isBootStrappedAuthenticated = true;
}
}
private void BootStrapUnauthentiated()
{
if (!_isBootStrapped)
{ // minimal bootstrap for launch but user not yet known, eg logon screen
BootStrapHttp(Context);
BootStrapper.RegisterInfrastureAdapters();
_isBootStrapped = true; // just a connection, if no persisted cookie, the may not be authenticated yet
}
}
}

Confusion with attaching/detaching and different ObjectContext object

I open a new MessagesWindow which has this code:
namespace Newsletter.UI
{
public partial class MessagesWindow : Window
{
MessageService msgService;
public MessagesWindow()
{
InitializeComponent();
msgService = new MessageService();
}
private void CreateButtonClick(object sender, RoutedEventArgs e)
{
var createMessageWindow = new CreateMessageWindow { Owner = this };
createMessageWindow.ShowDialog();
gridMessages.ItemsSource = from msg in msgService.GetAllMessages()
select msg;
}
private void messagesWindow_Loaded(object sender, RoutedEventArgs e)
{
gridMessages.ItemsSource = from msg in msgService.GetAllMessages()
select msg;
}
private void EditButtonClick(object sender, RoutedEventArgs e)
{
if (gridMessages.SelectedItem == null)
MessageBox.Show("You have to choose the message first.");
else
{
var selectedMessage = (Message)gridMessages.SelectedItem;
var editMessageWindow = new EditMessageWindow(selectedMessage);
editMessageWindow.Owner = this;
editMessageWindow.ShowDialog();
}
gridMessages.ItemsSource = from msg in msgService.GetAllMessages()
select msg;
}
}
}
I open a new window with EditButtonClick where I want to edit my Message. The code of the EditMessageWindow:
namespace Newsletter.UI
{
public partial class EditMessageWindow : Window
{
private Message editMessage;
private MessageService messageService;
public EditMessageWindow(Message message)
{
InitializeComponent();
editMessage = message;
messageService = new MessageService();
}
private void CreateMessageWindowLoaded(object sender, RoutedEventArgs e)
{
subject.Text = editMessage.Subject;
messageContent.AppendText(editMessage.Content);
senderComboBox.ItemsSource = messageService.GetAllSenders();
mailingListComboBox.ItemsSource = messageService.GetAllMailingLists();
}
private void SaveClick(object sender, RoutedEventArgs e)
{
editMessage.Date = DateTime.Now;
editMessage.Content = messageContent.Text;
editMessage.MailingList.Add(messageService.GetAllMailingLists()[mailingListComboBox.SelectedIndex]); //ERROR
editMessage.Sender = messageService.GetAllSenders()[senderComboBox.SelectedIndex];
editMessage.Subject = subject.Text;
editMessage.HasAttachments = false;
messageService.EditMessage(editMessage);
Close();
}
}
}
I get an error on SaveClick:
The relationship between the two objects cannot be defined because
they are attached to different ObjectContext objects.
Finally, MessageService code:
namespace Newsletter.Services
{
public class MessageService
{
private NewsletterEntities _context;
public MessageService()
{
_context = new NewsletterEntities();
}
public void AddMessage(Message newMessage)
{
_context.Messages.AddObject(newMessage);
_context.SaveChanges();
}
public void EditMessage(Message editMessage)
{
var messageToChange = (from m in _context.Messages where editMessage.MessageID == m.MessageID select m).FirstOrDefault();
if (messageToChange != null)
{
messageToChange = editMessage;
_context.SaveChanges();
}
}
public List<Message> GetAllMessages()
{
return (from m in _context.Messages select m).ToList();
}
public List<MailingList> GetAllMailingLists()
{
var query = from m in _context.MailingLists select m;
return query.ToList();
}
public List<Sender> GetAllSenders()
{
var query = from m in _context.Senders select m;
return query.ToList();
}
public void DeleteMessage(Message message)
{
List<MailingList> mailingLists = new List<MailingList>();
foreach(MailingList ml in message.MailingList.ToList())
{
ml.Message.Remove(message);
}
_context.Messages.DeleteObject(message);
_context.SaveChanges();
}
}
}
I'm getting consfused with all those layers and contexts. I know I should probably somehow detach the message, do something with it and attach but I don't know where and how. Should I do it in the service layer in MessageService, UI layer, or maybe DAL layer where I have all my entities? Or should I redesign my solution and do the context logic in different place?
you appear to have the setup of context per window. that will have 2 impacts on how you maintain the objects within the context.
You do not want to pass objects from form to form. instead you will pass the ID(s) from form to form and load the entity within the context.
As an entity is updated within one context you will need to notify the other windows/contexts of the change so they can refresh their data.
here is an MSDN article detailing the process of context per form. The article uses NHibernate, but the process would be almost identical for EF and DbCotext
http://msdn.microsoft.com/en-us/magazine/ee819139.aspx

Categories

Resources