none
Dependency injection in win forms and call registered form

    Question

  • I use simple injector. I've registered my FormUserNew:

    _container.RegisterForm<FormUsersNew>();

    which is called from FrmMain (main form), however i am not sure how should i take instance of that in FrmMain then call it.

    Here's my code below:

        static class Program
        {
            static void Main()
            {        
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Bootstrap();
    
                Application.Run(_container.GetInstance<FormMain>());
    
            private static void Bootstrap()
            {
                _container = new Container();
                _container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
                _container.Register<IUserService, UserService>(Lifestyle.Scoped);
                _container.Register<IUserTypeService, UserTypeService>(Lifestyle.Scoped);     
                _container.Register<FormMain>();
                _container.RegisterForm<FormUsersNew>();   //<===========
                _container.Verify();         
            }
        }
    
    
     public partial class FormUsersNew
        {
            private readonly Sektor _sektor;
            private readonly IUserService _userService;
            private readonly IUserTypeService _userTypeService;
    
            public FormUsersNew(IUserService userService, IUserTypeService userTypeService, EnumSector sector)
            {
                InitializeComponent();
                _sektor = sektor;
                _userService = userService;
                _userTypeService = userTypeService;
            }

    How then to call FormUsersNew to use my dependency injection ? :

    public partial class FormMain
    {
    
       private void BtnOpen_Click(object sender, EventArgs e)
       {
             //call FormUserNew <=======================
             //var form = new FormUsersNew(EnumSector.Fire);
             //form.ShowDialog();
       }
    }
    • Moved by CoolDadTx Tuesday, May 28, 2019 1:56 PM Winforms related
    Saturday, May 25, 2019 6:52 PM

All replies

  • In all my usage in using DI over the years, I have never seen a form being used in an IoC container and injected into another object. 

    What lead you to trying to do it?

    And what type of program is this Web, desktop or what?
    • Edited by DA924x Saturday, May 25, 2019 7:51 PM
    Saturday, May 25, 2019 7:38 PM
  • This is Windows Forms project. Look here: Simple injector windows forms


    • Edited by JimmyJimm Saturday, May 25, 2019 8:06 PM
    Saturday, May 25, 2019 8:05 PM
  • It's kind of strange that the link on one hand is talking about the MVC UI design pattern. But on the other hand, it does not talk about the MVP pattern. which can be used for Windows and Web forms. As a matter of fact, the 3 UI design patterns can be used by Windows or Web forms. But MVP would be what I would use for Windows form, which are presented later on in this post.

    Yes, I can see that DI is being used and that a Windows form can be injected. But really,  what the link is really showing is seperation of concerns and loose coupling via usage of Interface.

    https://en.wikipedia.org/wiki/Separation_of_concerns

    https://www.c-sharpcorner.com/blogs/understanding-interfaces-via-loose-coupling-and-tight-coupling

    But in talking about the link you have presented about DI and a Windows form is that it's not talking about the speration of duty that would be implemented by using the MVP UI design pattern where DI by use of Interface for Presenter could be DI into the form class and seperation of duty applied.

    https://www.codeproject.com/Articles/228214/Understanding-Basics-of-UI-Design-Pattern-MVC-MVP

    So what should be happening is the MVP Presenter is DI into the form class, becuase the Presenter is using an IPresenter. And through the Presenter,  it could use  the domain by usage of a service layer or a repository layer that has been DI into the Presenter class. 

    The Windows form should be unaware of the Repository directly with direct access to the Repository,   the service layer or even the bussiness layer, becuase SoD is being applied at the UI or presentation layer due to the implementation of the MVP UI design pattern where you could implement DI using the MVP Presenter injecting it into the form class.

    I suggest that you watch all the shows, but the Windows form show in VB will be of interest to you in how to implement the MVP pattern using it  with C#.

    http://polymorphicpodcast.com/shows/mv-patterns/

    When it talks about the Service Layer, think to yourself that you can implement an IService and remove the logic on how the Service class is  self-instancing itself and use the IoC container instead and DI the presenter and the service layer into the form class.

    A couple of other things, like using the Layered Architectural Style or even N-Tier  that further implements SoC.

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ee658117(v=pandp.10)

    Take the tutorial class and make it work with MVP and also make it work with DI for the BLL and DAL objects.  the BLL object using an interface would be injected into the Presenter and the DAL object injected into the BLL object.

     https://www.codeproject.com/Articles/36847/Three-Layer-Architecture-in-C-NET

    They do have IoC solutions where you can register all the classes at once that are using interface in a classlib project by pointing the classlib.  I forget what that technology in an IoC is called.

     


    • Edited by DA924x Sunday, May 26, 2019 2:57 AM
    Saturday, May 25, 2019 11:29 PM
  • I have already separation for my solution projects. I have forms which contains their services dependencies (all by inerfaces), then i have services like UserService, OrderService etc also having dependencies using interfaces. For example in UserService i have injection in ctor for instance for IUserRepository (dal). Repositories itself also having interfaces. I also got entites like User. I think it's fine, all could be tested easly. The one thing i am missing is with forms itself and the container. What could i change in my code that i could use container? Please check below my almost full code to get better picture of what;s there :

     
    static class Program
        {
            private static FormSplashScreen _splash;
            private static bool isDebug = false;
            private static Container _container;
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {        
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                Bootstrap();
    
      Application.Run(_container.GetInstance<FormMain>());
    
    
       private static void Bootstrap()
            {
                _container = new Container();
                // _container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
                _container.Register<IDbManager>(() => new DbManager(ConnectionDbType.SqlServer));
                _container.Register<IUserService, UserService>();
                _container.Register<IUserTypeService, UserTypeService>();
                _container.Register<IUserRepository, UserRepository>();
                _container.Register<IUserTypeRepository, UserTypeRepository>();         
                _container.RegisterForm<FormMain>();
                //_container.RegisterForm<FormUsersNew>();
                _container.Verify();         
            }
    
        }



    Starting Form: FormMain and this is also where the problem is on var form = new FormUsersNew i put all arguments which i want to be leave to container but in FormMain container object from Program.cs in not accessible:


     public partial class FormMain
        {
            public FormMain()
            {
                InitializeComponent();
                //this.AutoScaleMode = AutoScaleMode.Dpi;
            }
    
    
      private void BtnUserNew_Click(object sender, EventArgs e)
            {
                var form = new FormUsersNew(new UserService(new UserRepository(new DbManager(ConnectionDbType.SqlServer))),
                                                             new UserTypeService(new UserTypeRepository(new DbManager(ConnectionDbType.SqlServer))),
                                                             Sector.Fire);
                form.ShowDialog();
            }
    
    }




    ForUserNew where i use dependencies like UserService:


     public partial class FormUsersNew : IFormUsersNew
        {
            private readonly Sektor _sektor;
            private readonly IUserService _userService;
            private readonly IUserTypeService _userTypeService;
    
            public FormUsersNew(IUserService userService, IUserTypeService userTypeService, Sektor sektor)
            {
                InitializeComponent();
                _sektor = sektor;
                _userService = userService;
                _userTypeService = userTypeService;
            }
    
       private void BtnClose_Click(object sender, System.EventArgs e)
            {
                Close();
            }
    
     private void BtnAccept_Click(object sender, System.EventArgs e)
            {
    _userService.Add(new User()
                    {
                        Adres = txtAdres.Text,
                        UserType = 1;
                    });
    }

    UserService:


     public class UserService : IUserService
        {
            private readonly IUserRepository _userRepository;
    
            public UserService(IUserRepository userRepository)
            {
                _userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
            }
    
            public IEnumerable<User> SearchByName(string username)
            {
                return _userRepository.SearchByName(username);
            }
    }

    IUserRepository:

       public interface IUserRepository : IRepository<User>
        {
        }
    IRepository:

      public interface IRepository<T> where T : class, new()
        {
            IEnumerable<T> SearchByName(string username);
            T SearchById(string id);
            void Update(T entity);
            void Remove(T entity);
            void Add(T entity);
            IEnumerable<T> GetAll();
        }










    • Edited by JimmyJimm Sunday, May 26, 2019 8:22 AM
    Sunday, May 26, 2019 7:35 AM
  • I have already separation for my project i have forms then i have services like UserService - in UserService i have injection of for instance in ctor IUserRepository.

    How did you architect the solution? Did you put everything into  one project? Did you use the Layered  Style where you have a presentation layer, (the Windows form project), and then you have a possible business layer, a service layer and repository layer, which all the layers other than the presentauion layer are classlib projects?

    You should read the information about Layered and N-Tier.

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ee658117(v=pandp.10)

    You should follow and understand how a Layered solution is created.

     https://www.codeproject.com/Articles/36847/Three-Layer-Architecture-in-C-NET

    Everything about MVP how it works and how  to use it is in the shows, which is a UI design pattern that can be used for Windows form and ASP.NET Web form proacts. http://polymorphicpodcast.com/shows/mv-patterns/

    Until you understand what is happening with Layered architectural style and the MVP UI design pattern, then you can  do things proplerly in using SoC with Dependency Injection.

    I don't have an MVP example you can look at and understand, becuase code I have and use is ASP.NET MVC

    More on MVP

    https://lostechies.com/derekgreer/2008/11/23/model-view-presenter-styles/

    This too has a Windows form project that is using MVP.

    https://markheath.net/post/model-view-presenter-winforms

    I will help you, but first, we need to be on the same page.

    Sunday, May 26, 2019 8:54 AM
  • Yes, all what you mentioned is separated in diffrent projects like repositories, services, forms, shared data etc. I still think its ok the only one thing is how to access container from outside program.cs. i see one solution at the moment either i put dependencies for forms into properties instead to constructors and define default object inside theor body. In this approach i would still have possibility to test them. What you think?
    Sunday, May 26, 2019 1:02 PM
  • I am not a fan of placing a form class into an IoC. I have never seen it done not with Windows, ASP.NET or WPF form projects. If the form is to be instanced then it should be done with the 'new' keyword.

    The only dependency injection that should be done at the form/view level is the Presenter that is using an IPresenter in using the Model View Presenter UI design pattern with the Presenter being injected  into a form class.

    Any other classlib projects you will want to use should be referenced by the Presenter classlib project with classes in those projects implementing an Interface so that they can be DI where they are needed.

    The view/form should not beware of anything but the Presenter,  form controls on the form/view, form events, control events and  everything else deferred to the Presenter, making the UI dumb as dumb as possible by implementing seperation of duty. 

    I am also not a fan of the generic Repository pattern, becuase the Repositroy pattern is a Domain pattern used in Domain Driven Design and not a persistence pattern that somehow got twisted from its original intent.

    https://martinfowler.com/eaaCatalog/repository.html

    https://programmingwithmosh.com/net/common-mistakes-with-the-repository-pattern/

    https://blog.sapiensworks.com/post/2012/03/05/The-Generic-Repository-Is-An-Anti-Pattern.aspx

    You should consider using the DAO pattern with the DAO class/object implementing an Interface, which is what I have used for data persistence over the years on a per table basis in the low level mapping with the database technology/DAL, particularly so if the Repositroy object is anemic of any domain logic that makes it just a glorified DAO.

     https://blog.sapiensworks.com/post/2012/11/01/Repository-vs-DAO.aspx

    In the above link it talks about the DTO.

    https://en.wikipedia.org/wiki/Data_transfer_object

    https://www.codeproject.com/Articles/1050468/Data-Transfer-Object-Design-Pattern-in-Csharp

    But if you insist upon using the generic repository pattern, then implement the UoW pattern in using the generic repository.

    https://www.codeproject.com/Articles/581487/Unit-of-Work-Design-Pattern

    Myself, I avoid the generic repository pattern, like the plunge,  and prefer the DAO pattern.

    https://www.infoworld.com/article/3117713/design-patterns-that-i-often-avoid-repository-pattern.html

    https://en.wikipedia.org/wiki/Data_access_object

    https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm

    And yes,  implementing an Interface on a class allows the class to be unit tested, becuase you can mock out the Interface and the class.

    You should use the 'new is glue'  principle on everything else but using an IoC container on a form class, IMO. 

    https://ardalis.com/new-is-glue

     

     

    Sunday, May 26, 2019 3:40 PM
  • by saing "view" - you mean Form? Could you be so kind and based on my code show me an example how it could be transformed into what you saing, that would be evry helpfull to get a picture. Many thanks DA924x

    Sunday, May 26, 2019 5:05 PM
  • Here you go I took the MVP Windows form project and converted over to C# using MVP and dependency injection of the BLL and Service Layer. 

    http://polymorphicpodcast.com/shows/mv-patterns/

    I will also add in the centralized exception handling link for the presentation layer project that means that any unhandled exception thrown in any layer is caught by the CEH or Global Exception Handler. It means that you don't need a try/catch in any code in any layer to catch exceptions.

     https://www.codeproject.com/Articles/43182/Centralised-Exception-Handling-in-C-Windows-Applic

    HTH 

    You are working me man working me. :)

    The architectural structure

    The code..

    using System;
    using System.Windows.Forms;
    using BLL;
    using SimpleInjector;
    using ServiceLayer;
    
    namespace WindowsFormsApplication1
    {
        static class Program
        {
           public static Container container;
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                Bootstrap();
                
                Application.Run(new ProductEditorView());
            }
    
            public static void Bootstrap()
            {
                // Create the container as usual.
                container = new Container();
    
                // Register your types, for instance:
                container.Register<IBusProduct, BusProduct>();
                container.Register<IService, Service>();
    
                // Optionally verify the container.
                container.Verify();
            }
        }
    }
    

    using System;
    
    namespace WindowsFormsApplication1.IViews
    {
         public interface IProductEditorView
        {
            int ProductID { get; }
            string ProductDescription { get; }
            event EventHandler<EventArgs> Save;
        }
    }
    

    using System;
    using WindowsFormsApplication1.IViews;
    using BLL;
    using Entities;
    
    namespace WindowsFormsApplication1.Presenters
    {
        public class ProductEditorPresenter
        {
            private IProductEditorView mView;
            private IBusProduct _busproduct;
    
            public ProductEditorPresenter(IProductEditorView view, IBusProduct busproduct)
            {
                this.mView = view;
                _busproduct = busproduct;
                this.Initialize();
            }
    
            private void Initialize()
            {
                this.mView.Save += new EventHandler<EventArgs>(mView_Save);
            }
    
            private void mView_Save(object sender, EventArgs e)
            {
                DtoProduct dto;
    
                try
                {
                    dto = new DtoProduct();
                    dto.Description = this.mView.ProductDescription;
                    dto.ID = this.mView.ProductID;
                    _busproduct.Save(dto);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    throw;
                }
            }
    
        }
    }
    
    using System;
    using System.Windows.Forms;
    using WindowsFormsApplication1.IViews;
    using WindowsFormsApplication1.Presenters;
    using BLL;
    
    namespace WindowsFormsApplication1
    {
        public partial class ProductEditorView : Form, IProductEditorView
        {
            private ProductEditorPresenter mPresenter;
           
            public ProductEditorView()
            {
                InitializeComponent();
                Program.Bootstrap();
            }
    
            protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);
                mPresenter = new ProductEditorPresenter(this, Program.container.GetInstance<BusProduct>());
            }
    
            private void btnSave_Click(object sender, EventArgs e)
            {
                Save?.Invoke(this, EventArgs.Empty);
            }
    
            #region IProductEditorView Members
    
            public int ProductID => Convert.ToInt32(this.txtProductID.Text);
    
            public string ProductDescription => this.txtProductDescription.Text;
    
            public event EventHandler<EventArgs> Save;
    
            #endregion
    
        }
    }
    

    using Entities;
    
    namespace BLL
    {
        public interface IBusProduct
        {
            void Save(DtoProduct dto);
        }
    }
    
    =================================================
    
    using Entities;
    using ServiceLayer;
    
    namespace BLL
    {
        public class BusProduct : IBusProduct
        {
            private IService _service;
    
            public BusProduct(IService service)
            {
                _service = service;
            }
            public void Save(DtoProduct dto)
            {
                _service.Save(dto);
            }
        }
    }
    

    using Entities;
    
    namespace ServiceLayer
    {
        public interface IService
        {
            void Save(DtoProduct dto);
        }
    }
    
    ================================================
    using System;
    using Entities;
    
    namespace ServiceLayer
    {
        public class Service : IService
        {
            public void Save(DtoProduct dto)
            {
                throw new NotImplementedException();
            }
        }
    }
    

    namespace Entities
    {
        public class DtoProduct
        {
            public string Description { get; set; }
           
            public int ID { get; set; }
        }
    }
    


    Monday, May 27, 2019 1:02 AM
  • Hi,

    Thanks for your answer, i staterted new project from scratch, can i provide you link to it so we are inline?

    I have also few questions:

    1. As i know one presenter has his one view. But can one presenter has dependencies to other presenters or views?

    2. Let's say i have some business logic which uses e.g Order and Customer, lets say i have Order and Customer models classes. I can of course make OrderService and CustomerService. But Is it good practice to create CustomerOrderService that could take both Customer and Order models and implement some logic in that service? Because as far as i learnt business logic should go to services.

    3. Can presenter also make some business logic using service/-s?



    • Edited by JimmyJimm Tuesday, May 28, 2019 12:05 PM
    Tuesday, May 28, 2019 11:12 AM
  • There is no problem using IoC with Winforms. It doesn't work any different than any other place you might do so. The only thing remotely different about Winforms (and WPF for that matter) is that projects tend to just new up the form instances rather than injecting them. However that is really irrelevant for using IoC. 

    When you want to create an instance of anything in the IoC you simply need to get the container that has the registrations. In some frameworks like MVC this is handled automatically in most cases but you can always do it manually. The issue is lifetime scope. In most apps that need access to the container outside the normal "flow" you need to put the container into a global variable of some sort (a static property on a static class). Some IoC libraries handle this for you automatically. In some cases you might also consider simply hooking into the existing (limited) framework implementation of IServiceProvider. Then you have access to it anywhere. Here's a simple approach.

    static class Program
    {
        [STAThread]
        static void Main ()
        {
            Bootstrap();
    
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    
        static void Bootstrap ()
        {
            //Register whatever
            Container.RegisterForm<MyForm>();
        }
    
        //Put it here but you can put it anywhere provided it is accessible to all the other code you want
        public static Container Container { get; } = new Container();
    }    
    
    //Couldn't find the impl of RegisterForm so I created a simple one
    static class ContainerExtensions
    {
        public static Container RegisterForm<T> ( this Container source ) where T: Form
        {
            source.Register<T>();
    
            return source;
        }
    }

    Then to use it anywhere.

    //Every time this button is clicked it opens up a modeless form from the container
    private void Button1_Click ( object sender, EventArgs e )
    {
        //Get the global container
        var child = Program.Container.GetInstance<MyForm>();
        child.Show();
    }
    Note that if you're building an extensible app then we tend to put the "host" stuff into a host interface. This is sort of what IServiceProvider is for. You might find hooking into this implementation easier.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, May 28, 2019 1:56 PM
  • Thanks for your answer, i staterted new project from scratch, can i provide you link to it so we are inline?

    Ok

    1. As i know one presenter has his one view. But can one presenter has dependencies to other presenters or views?

    It's one IView, one view/form and one presenter that ties it altogether. A form/view can call another form/view. But the iView/view-form/presenter are independent from any other iView/view-from/presenter. 

    Of course a view/form can instance another view/form,  and a view/form can host a user control that would have its own iView/usercontrol view/presenter. 

    https://en.wikipedia.org/wiki/Model–view–presenter

    <copied>

    MVP is a user interface architectural pattern engineered to facilitate automated unit testing and improve the separation of concerns in presentation logic:

    • The model is an interface defining the data to be displayed or otherwise acted upon in the user interface.
    • The view is a passive interface that displays data (the model) and routes user commands (events) to the presenter to act upon that data.
    • The presenter acts upon the model and the view. It retrieves data from repositories (the model), and formats it for display in the view.

    <end>

    The presenter acts upon the model on the behalf of the view, the model the domain objects. The presenter can act upon more than one domain object based on business needs.

    https://en.wikipedia.org/wiki/Business_logic

    https://martinfowler.com/eaaCatalog/domainModel.html

    Just an example of the domain model

    https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design

    Another example of the domain model.

    http://www.bradoncode.com/blog/2013/08/repository-vs-domain-model-vs-data.html

    3. Can presenter also make some business logic using service/-s?

    The service layer mediates communications between the presenter in MVP and the repository or data access layer not unlike its usage in MVC, which I am accustom to,  and the SL can have validation business logic.

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/models-data/validating-with-a-service-layer-cs


    Tuesday, May 28, 2019 3:02 PM
  • i will take a look on that. Meantime can you tell me whether according to MVP can one presenter besides of his View call also other presenter? For instance:

    public class APresenter
    {         
         public APresenter(IXView xview, IBPresenter bPresenter)        
         {
         }
    }

    as you can see i injected also IBPresenter, so APresenter can use it, is it legal according to MVP?

    Moroever what if there would be CPresenter for CView opening from BView, could i use his CPresenter in APresenter or BPresenter?

    Generally question is can whatever rpesenter/-s be used in other presenters?

    Tuesday, May 28, 2019 3:25 PM

  • as you can see i injected also IBPresenter, so APresenter can use it, is it legal according to MVP?

    Moroever what if there would be CPresenter for CView opening from BView, could i use his CPresenter in APresenter or BPresenter?

    Generally question is can whatever rpesenter/-s be used in other presenters?

    It's something I wouldn't recommend doing. And if you were to present something like this for a code review  by professionals, it would be rejected.

    Tuesday, May 28, 2019 3:53 PM
  • Hmm, i went through very nice youtube tutorial by Robert G Marquez - 10 videos. Look at 10th video (last one from series) here:

    https://www.youtube.com/watch?v=0CVJ24nYt5I

    at 35:39 you will see his MainPresenter has dependency to IHelpAboutPresenter.

    Tuesday, May 28, 2019 8:46 PM
  • Hmm, i went through very nice youtube tutorial by Robert G Marquez - 10 videos. Look at 10th video (last one from series) here:

    https://www.youtube.com/watch?v=0CVJ24nYt5I

    at 35:39 you will see his MainPresenter has dependency to IHelpAboutPresenter.

    I can't say that I would implement that. One could have a presenter that worked with multiple views much like a MVC controller would have views with ActionMethods for each view the controller was working with like Customer views  of create, update, delete and details for a Customer. And if that's the case,  there could be one presenter controlling all the views.

    But for me, I like to keep things simple, and IMO, the simpler the better. I have seen too many times where a developer went yippee ki yay cowboy and wondered why someone didn't stop the developer.

    So for me and what I have seen in using MVP is one iView, view and presenter for a given view making things a whole lot easier to implement and unit test

    Tuesday, May 28, 2019 10:33 PM
  • If we have MainPresenter which controls MainView - this is main form. On main form i have button to open other form let's say HelpView which also has HelpPresenter responsible for that view. If it's opened from MainView and it's Mainpresenter should open MainPresenter to open HelpPresenter to open HelpView. That;s what he done on his project.  How this situation could be done if not call HelpPresenter from MainPresenter then?

    I provided my project below, you can download it so we can work together a bit. If you open for instance MainPresenter class there is injection to IHelpAboutPresenter at ctor:

     public MainPresenter(IMainView mainView, IErrorMessageView errorMessageView, IHelpAboutPresenter helpAboutPresenter)// base: (errorMessageView

    My project

    If you say it's not valid what should i change in this case to be as you said correct?



    • Edited by JimmyJimm Wednesday, May 29, 2019 7:00 AM
    Wednesday, May 29, 2019 5:52 AM
  • I have no problem in how you are doing the presenters. If that's what you have learned by watching some shows,  then fine, becuase that's the beauty of using an Interface.

    However, the rest of the architect is suspect. The usage of the generic Repository pattern confines you to what is only happening in that Repository object. You can't call out to another Repository object to shape data via means of a DTO and return combination of data to the presenter nor can you send combination of data back to the backend to be persisted 

    The Repository object you have shown  is no more than a glorified DAO that has limited scope based on the static members of the Repository object. A Repository object doesn't do Add() or Update(), and it can't shape data. It can't call out to the method in another Repository object and have it do something on its behalf, unlike a DAO or a non generic Repository object.

    Maybe one day you want to use a WebAPI or WCF service that the Windows form application is the client to the WebAPI or WCF service in a multiple user scenario. The way you are going, the solution is not scalable not easily, which is one of the reasons to use layered, n-tier  or one of the other architectural styles, scalability.

    Maybe you'll want to change out the entire back-end from MS SQL Server to Oracle or from Entity Framework to nHibernate or  stop using ADO.NET with database command objects and T-SQL or stored procedures. Or maybe, you want to take the whole backend logic and use it with an Web UI program that's using MVP too, MVC or even WPF using MVVM, scalability.

    One of the things that helps you to decouple is the DTO, becuase all the client sees is the DTO(s) and it's unaware of what is happing with the backend.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Data.Entity;
    using System.Data.Entity.Core.EntityClient;
    using System.Data.Entity.Core.Objects;
    using System.Data.Entity.Infrastructure;
    using System.Data.SqlClient;
    using Entities;
    using DAL.Model;
    
    namespace DAL.DAO
    {
        public class DAOStudent : IDAOStudent
        {
            public DTOStudent GetStudentById(Int32 id)
            {
                var dto = new DTOStudent();
                using (var context = new CUDataEntities())
                {
                    var student = (context.Students.Where(a => a.StudentID == id)).SingleOrDefault();
    
                    if (student != null)
                    {
                        dto.StudentID = student.StudentID;
                        dto.FirstName = student.FirstName;
                        dto.LastName = student.LastName;
                        dto.EnrollmentDate = student.EnrollmentDate;
    
                        var enrolllments =  new DAOEnrollment().GetEntrollmentsByStudentId(id).ToList();
                        var courses = new DAOCourse().GetCoursesByStudentCourseId(student.StudentID).ToList();
    
                        dto.EnrollsandCourses = (from a in enrolllments
                                      join b in courses on a.CourseID equals b.CourseID
                        select new  DTOEnrollandCourse()
                         { Title = b.Title, Credits = b.Credits, Grade = a.Grade }).ToList();
                    }
                }
    
                return dto;
            }
            public void CreateStudent(DTOStudent dto)
            {
                using (var context = new CUDataEntities())
                {
                    var student = new Student
                    {
                        FirstName = dto.FirstName,
                        LastName = dto.LastName,
                        EnrollmentDate = dto.EnrollmentDate
                    };
    
                    context.Students.Add(student);
                    context.SaveChanges();
                }
            }
    
            public void DeleteStudent(int id)
            {
                Student student;
                using (var context = new CUDataEntities())
                {
                    student = (context.Students.Where(a => a.StudentID == id)).SingleOrDefault();
                }
    
                using (var newContext = new CUDataEntities())
                {
                    newContext.Entry(student).State = System.Data.Entity.EntityState.Deleted;
                    newContext.SaveChanges();
                }
            }
    
            public List<DTOStudent> GetStudents()
            {
               
                var dtos = new List<DTOStudent>();
    
                using (var context = new CUDataEntities())
                {
                    var students = context.Students.ToList();
    
                    foreach(var stud in students)
                    {
                        var dto = new DTOStudent
                        {
                            StudentID = stud.StudentID,
                            FirstName = stud.FirstName,
                            LastName = stud.LastName,
                            EnrollmentDate = stud.EnrollmentDate
                        };
    
                        dtos.Add(dto);
                    }
                }
    
                return dtos;
            }
    
            public void UpdateStudent(DTOStudent dto)
            {
                var student = new Student();
    
                using (var context = new CUDataEntities())
                {
                    student = (context.Students.Where(a => a.StudentID == dto.StudentID)).SingleOrDefault();
                }
    
                if (student != null)
                {
                    student.FirstName = dto.FirstName;
                    student.LastName = dto.LastName;
                    student.EnrollmentDate = dto.EnrollmentDate;
                } 
    
                using (var dbcontext = new CUDataEntities())
                {
                    if (student != null)
                    {
                        dbcontext.Entry(student).State = EntityState.Modified;
                        dbcontext.SaveChanges();
                    }
                }
            }
        }
    }

    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    
    namespace Entities
    {
       [DataContract] 
        public class DTOStudent
        {
            
            private DTOResponse dtor = new DTOResponse();
    
            [DataMember]
            public Int32 StudentID { get; set; }
    
            [DataMember]
            public string LastName { get; set; }
    
            [DataMember]
            public string FirstName { get; set; }
    
            [DataMember]
            public DateTime? EnrollmentDate { get; set; }
    
            [DataMember]
            public virtual ICollection<DTOEnrollandCourse> EnrollsandCourses { get; set; }
    
            [DataMember]
            public DTOResponse DtoResponse
            {
                get { return dtor; }
                set { dtor = value; }
            } 
        }
    }

     

    • Edited by DA924x Wednesday, May 29, 2019 10:48 AM
    Wednesday, May 29, 2019 10:41 AM