I am working on a webform project, where I want to implement MVP Pattern.
I have gone through few articles and project based on MVP. It seems fine to me.
At most of the places, If there is any need to display error message, it has been made
a method in the view interface. I am giving an example here for clarity.
public interface IAdminSettingsView
{
string Name { get; set; }
string Password { get; set; }
string Email { get; set; }
void ShowErrorMessage(string errorMessage);
}
here is my control implementing IAdminSettingsView
public partial class AdminSettingsEdit : BaseControl, IAdminSettingsView
{
private AdminSettingsPresenter _adminSettingsPresenter;
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
_adminSettingsPresenter = new AdminSettingsPresenter(this);
}
protected void BtnSave_Click(object sender, EventArgs e)
{
_adminSettingsPresenter.Save();
}
#region Implementation of IAdminSettingsView
public string Name
{
get { return AdminName.Text; }
set { AdminName.Text = value; }
}
public string Password
{
get { return AdminPassword.Text; }
set { AdminPassword.Text = value; }
}
public string Email
{
get { return AdminEmail.Text; }
set { AdminEmail.Text = value; }
}
public void ShowErrorMessage(string errorMessage)
{
lblErrorMessage.Text = errorMessage;
}
#endregion
}
here is my presenter
public class AdminSettingsPresenter
{
public AdminSettingsPresenter(IAdminSettingsView view)
{
_view = view;
}
private IAdminSettingsView _view;
public void Save()
{
try
{
//Trying Save Data Here
}
catch (Exception exception )
{
_view.ShowErrorMessage("Couldnt Save Data");
}
}
}
My question is, how can I seperate Error Related messages into a different Interface and then make a communication between them. for example if I have an interface
interface IShowErrorMessage
{
//somemethod here
}
how to use this interface to work with my main IAdminSettingsView interface.
Your help will be appreciated. If there is any better solution to this problem, I would love to hear.
Regards
Parminder
At the lowest level (for example the Utility DLL) I put the classes for error handling. One of which is a interface that forms can implement. On startup the software registers the form implementing the interface with the low level DLL. This form can be defined at the highest level (the EXE).
When an error occurs at any level of the software the appropriate calls can be made to the error framework and if a form implemented the display error interface then a form will display at that point.
As an aside I do this as well for status and progress messages. There is a IStatusDisplay interface and a IProgressDisplay interface. The EXE registers the forms or classes that implement these interfaces
First, in IShowErrorMessage, define the properties/methods needed to show an error message.
Something like:
interface IShowErrorMessage
{
void Show(string errorMessage);
}
Next, your view will implement that interface.
The view's implementation of Show(string) will setup a literal.
The presenter will remain unchanged.
Create some unit tests and you are good!
Hope it helps.
Related
I have some actions in a view.
public class AView
{
public Action Show { get; set; }
public Action Hide { get; set; }
}
and I'm trying to set those actions inside another class, by passing them as a parameter (I don't want to pass the whole class)
_reloader.SetupActions(Show, Hide);
Reloader is abstract, because there might be different ways of handling how Hide/Show must behave depending on the scenario we're in.
public abstract class Reloader : IReloader
{
public void SetupActions(Action show, Action hide)
{
show = Show;
hide = Hide;
}
protected virtual void Show() { ... } //what should be done when Show is invoked
protected virtual void Hide() { ... } //same for Hiding
}
And for the current view, I might be using a RapidReloader, SafeReloader, etc. This bit is irrelevant, except that the injected reloader is specific to the current view.
Now my problem is simple and logic : when I'm in SetupActions, all parameters are null (because Actions haven't been set), and setting Show into null obviously does not work.
What can I do so that when Show.Invoke() happens my view, the ShowCode from the relevant reloader is called? I would like to avoid passing the whole view as a parameter.
Also, if you have a better design, I'm all ears. We might be in an XY problem situation
You will need to use System.ValueTuple nuget package if you don't use .Net Framework 4.7 or newer.
public interface IReloader
{
(Action Show, Action Hide) GetActions();
}
public abstract class Reloader : IReloader
{
public (Action Show, Action Hide) GetActions()
{
return (Show, Hide);
}
protected virtual void Show() { }
protected virtual void Hide() { }
}
public class FastReloader : Reloader { }
public class AView
{
public Action Show{ get; set; }
public Action Hide{ get; set; }
public void IwantTheNewActions()
{
var reloader = new FastReloader();
var actions = reloader.GetActions();
Show = actions.Show;
Hide = actions.Hide;
}
}
I've been struggling with this for a while... I have a programm written using the MVP pattern, I want to have a LogHandler class that must retrieve a string that corresponds to an ID provided in one of these methods, but it also needs to update the GUI, adding items to a listbox. So to simplyfy, imagine this:
if (name != "Peter")
{
Log.RegisterError(31, 4) //errorType, errorID
}
So in the Log class it would then get the string that matches the type and IDs provided and MessageBox it, but what if I want to add that string to a control on the form? I'm using views implemented by the forms to accomplish GUI updating, but since this is a static class I can't...
Also where should errors be checked and raised? Presenter? View? Model?
Thanks in advance
You could add callbacks in you Log class that other object could subscribe to.
Example:
In this example the Presenter can listen for an error code to be logged then receive the error string from the Log from the Model class
public class Logger
{
private static Dictionary<int, List<Action<string>>> _callbacks = new Dictionary<int,List<Action<string>>>();
public static void RegisterLoggerCallback(int errorType, Action<string> callback)
{
// Just using errortype in this exaple, but the key can be anything you want.
if (!_callbacks.ContainsKey(errorType))
{
_callbacks.Add(errorType, new List<Action<string>>());
}
_callbacks[errorType].Add(callback);
}
public static void RegisterLog(int errorType, int errorID)
{
// find error sring with codes
string error = "MyError";
// show messagebox
MessageBox.Show(error);
// tell listeners
if (_callbacks.ContainsKey(errorType))
{
_callbacks[errorType].ForEach(a => a(error));
}
}
}
public class Model
{
public Model()
{
}
public void DoSomething()
{
Logger.RegisterLog(1, 2);
}
}
public class Presenter
{
public Presenter()
{
Logger.RegisterLoggerCallback(1, AddToListbox);
}
private void AddToListbox(string error)
{
// add to listbox when errortype 1 is called somewhere
}
}
This is a very simple example but should give you an idea of a way to achive this.
I have a single page that has a number of controls configured a certain way depending on some condition (e.g. if it is a user accessing the page or an admin). How I currently achieve this is by having an interface for the settings which are common to all pages, and then extending classes which implement the properties specific to the type of user.
For example:
public interface Display_Type
{
string backgroundColor { get; }
}
public class AdminPage : Display_Type
{
string backgroundColor { get { return "orange"; } }
}
public class UserPage : Display_Type
{
string backgroundColor { get { return "blue"; } }
}
And my page's codebehind:
public partial class MyPage : System.Web.UI.Page
{
Display_Type pageSettings;
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
pageSettings = new AdminPage();
}
else
{
pageSettings = new UserPage();
}
// ...
string backgroundColor = pageSettings.backgroundColor;
// ... Do stuff with background color
}
}
This works fine for me, but since these settings are constant across the application, they seem to make more sense as static classes. However, I'm having trouble figuring out how to do this because I can't assign a static class to a variable.
My questions are:
Is there a better way I can accomplish what I'm trying to do here?
Or, if this is okay, how could I accomplish what I'm doing with static classes / members?
It may be worth noting that the user/admin example is not how I'm using this structure in my web application, and in fact has nothing to do with the user themselves but rather other factors such as request parameters.
Put your settings on the BasePage and have other pages derive from it.
You will set the settings only once.
public abstract class MyBasePage : System.Web.UI.Page
{
protected Display_Type PageSettings { get; private set; };
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
PageSettings = new AdminPage();
}
else
{
PageSettings = new UserPage();
}
}
}
public partial class MyPage : MyBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
// ...
string backgroundColor = PageSettings.backgroundColor;
// ... Do stuff with background color
}
}
This is not how I would do this, but if you are doing it this way, static classes have absolutely nothing to do with and no use in this situation.
You might consider having a single instance of each of the Display_Type classes stored somewhere to be reused, instead of creating a new one each time, though. This might end up being as a static variable... but that's not the same at all as a static class.
You can use a singleton to define your AdminPage and UserPage profile and add a static method GetDisplayType() to your implementation.
public static class PageTypes {
public static PageType Admin(/** stuff here */);
public static PageType User(/** stuff here */);
}
public class PageType {
readonly string _backgroundColor;
public PageType (/** stuff here */) {
_backgroundColor = backgroundColor;
}
public string BackgroundColor {
get {
return _backgroundColor;
}
}
So now, you can access them like this in your method:
if ((bool)Session["Is_Admin"])
{
PageSettings = PageTypes.Admin;
}
else
{
PageSettings = PageTypes.User;
}
I agree with Jakub about using the base class to prevent code duplication.
1. Is there a better way I can accomplish what I'm trying to do here?
Microsoft .NET has a built-in application settings implementation: setting files. Just use them if your settings aren't configurable by each user.
Application settings can be defined in a satellite assembly and overridden in the app.config or web.config of your application.
That's I find better to define such settings using setting files, which is a built-in, understandable and well-implemented solution and you've it out-of-the-box.
How to accomplish your goal using setting files?
You can use configuration by convention, and your background color settings will look like this:
AdminPage_BackgroundColor => #000000
UserPage_BackgroundColor => #FFFFFF
and so on
In your case, you've two background color settings for both pages, but if you'd need to configure background color for any of pages, you'd do this in your Page-derived class instance:
Properties.PagesStyle.Default[GetType().Name + '_' + "BackgroundColor"]
And you'll be able to get background color by page and from your settings file.
Let's implement this in your page class:
public partial class MyPage : System.Web.UI.Page
{
Color backgroundColor = null;
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
backgroundColor = Properties.PagesStyle.Default.AdminPage_BackgroundColor;
}
else
{
backgroundColor = Properties.PagesStyle.Default.UserPage_BackgroundColor;
}
// ... Do stuff with background color
}
}
Note settings files allow you to define strongly-typed values. Let's say you typed "UserPage_BackgroundColor" as System.Drawing.Color, designer will edit color by using a color picker, and when you access to this setting, you'll get a System.Color instead.
Before begin with another approach, check these useful links:
Settings files in MSDN: http://msdn.microsoft.com/en-us/library/aa730869(v=vs.80).aspx
Some other answer I did some time ago: Can a class library have an App.config file?
Recommended approach
There's a solid, stable and valuable way of styling Web sites: CSS.
Instead of creating your own styling approach, just play with CSS classes.
For example, in some CSS stylesheet you define both background colors for admin page and user page:
body.UserPage
{
background-color: #000;
}
body.AdminPage
{
background-color: #FFF;
}
Just imagine you've this ASP.NET page (I'll include standard XHTML markup only):
<html>
<head></head>
<body id="body" runat="server"></body>
</html>
In your code-behind code perhaps you can do this:
public partial class MyPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if ((bool)Session["Is_Admin"])
{
body.Attributes["class"] = "AdminPage";
}
else
{
body.Attributes["class"] = "UserPage";
}
}
}
This way you avoid:
Creating redundant settings since you use CSS as styling mechanism (don't reinvent the wheel!).
Compiling styling values: it's a client-side thing, because it's CSS.
To answer your second question, a implementation of a static solution:
public interface IDisplayType
{
string backgroundColor { get; }
}
public class AdminPage : IDisplayType
{
public string backgroundColor { get { return "orange"; } }
}
public class UserPage : IDisplayType
{
public string backgroundColor { get { return "blue"; } }
}
public static class PageProperties
{
private static AdminPage _adminPage = new AdminPage();
private static UserPage _userPage = new UserPage();
public static IDisplayType DisplayType { get
{
if ((bool)HttpContext.Current.Session["Is_Admin"])
{
return _adminPage;
}
return _userPage;
}
}
I also changed the type Display_Type to IDisplayType which gives a beter description of what it is.
You could then use the following code in your page.
string backgroundColor = PageProperties.DisplayType.backgroundColor;
I know that C# does not offer multiple inheritance. And I know there' are workarounds like this one for instance.
But here's a problem that I faced today, can't figure any ELEGANT workaround. I'll add some abstract code-sample so you get it quicker...
(let it be a real-life ASP.NET code - cause those "class A, class B" code-samples are really confusing):
public class AdminPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
//if not an admin - get out
if(!CurrentUserIsAdmin()) Response.End();
base.OnInit (e);
}
}
public class JQueryPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
RegisterJQueryScript();
base.OnLoad (e);
}
}
//now here's what I REALLY miss in C#
public class AdminJQueryPage : AdminPage, JQueryPage;
Compose out the functionality? This is better for Single Responsibility. You'd have to think carefully about your constructors.
interface IAdminPage {
public string AdminPageMethod();
}
interface IJQueryPage {
public string JQueryPageMethod();
}
internal class AdminPage : IAdminpage {
private string someString;
internal AdminPage(string value) {
this.someString = value;
}
public string AdminPageMethod() {
return "AdminPage result with some string: " + this.someString;
}
}
internal JQueryPage : IJQueryPage {
private int someNumber;
internal JQueryPage(int value) {
this.someNumber = value;
}
public string JQueryPageMethod() {
return "JQueryPage result with number: " + this.someNumber;
}
}
class AdminJQueryPage : IQueryPage, IAdminpage {
private readonly IAdminPage adminPage;
private readonly IJQueryPage jqueryPage;
public AdminJQueryPage(string someString, int someNumber) {
this.adminPage = new AdminPage(someString);
this.jqueryPage = new JQueryPage(someNumber);
}
public string AdminPageMethod() {
return this.adminPage.AdminPageMethod();
}
public string JQueryPageMethod() {
return this.adminPage.JQueryPageMethod();
}
}
If you really want multiple inheritance, look at Scala's traits
Edit: added passing of constructor values to composed out classes. Also made the classes internal (cannot be accessed or constructed outside the assembly) because they are only ever constructed by the AdminJQueryPage class, which is the 'public-facing' class.
I came from C++ too and dont miss it, especially since reading Refactoring [and using a non-OOTB tool for that].
You can use PostSharp to post process based on placing attributes on your AdminJQueryPage which would achieve the exact same effect.
Or you can Extract Method code into helper classes and call that (i.e., Joe's example)
Or you can put the helpers in a single base class and call from that.
Either way your code will be clearer.
It's only a matter of time before your mixins start overlapping, and then your general suite of techniques for managing that complexity needs to kick in - in C++, MI should only have been one tool in a suite - rather than a very sexy hammer.
its possible to fake a mixin by specifying a interface and creating extension methods for that interface. however I'm not use this will help overriding methods, only adding new ones. you are of course able to then call an extension method when overriding, but that is basically the same as extracting the methods to a helper class, but with a little more sugar
Even if it was possible, one problem with the semantics of an MI-based solution to the specific problem you raised is what happens on the markup side? The Render() method that generates the markup would run first in one class, and then in the other? That's probably not the behavior you want when both classes generate entire pages.
If you're open to solutions that are outside of the language itself, there are several elegant options in ASP.NET that will address the type of issue you raised (changing the actions taken during an event in the page life cycle). For example:
Page Adapters
Control Adapters
Custom user controls
HttpModules
Master Pages
Tag mapping
The best choice will of course depend on the details of your application. In case it's helpful, I cover those options in my book, including sample code: Ultra-Fast ASP.NET.
The simplest approach is to build a hierarchy - allow AdminPage to inherit from JQueryPage like so:
public class AdminPage : JQueryPage
{
protected override void OnInit(EventArgs e)
{
//if not an admin - get out
if(!CurrentUserIsAdmin()) Response.End();
base.OnInit (e);
}
}
public class JQueryPage : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
RegisterJQueryScript();
base.OnLoad (e);
}
}
//now here's what I REALLY miss in C#
public class AdminJQueryPage : AdminPage
My guess is some of this awkwardness comes from the ASP.NET page model, which uses overridden base class methods.
You can to do this with Interfaces
public interface IJQueryPage
{
}
public abstract class AdminPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
//if not an admin - get out
if(!CurrentUserIsAdmin()) Response.End();
base.OnInit (e);
}
protected override void OnLoad(EventArgs e)
{
if (this is IJQueryPage)
{
RegisterJQueryScript();
}
base.OnLoad (e);
}
}
public class AdminJQueryPage : AdminPage, IJQueryPage
{
}
i added a property 'WrmVersion' in interface IResourcePolicy but i am not getting those thing in the implementation side means here it should come in the List
view data. means SubItems.Add(((IResourcePolicy)Data).WrmVersion is not getting
This is the interface
public interface IResourcePolicy
{
DataVersion WrmVersion
{
get;
set;
}
bool ResourcePolicyEnabled
{
get;
set;
}
}
i am implementing it in
public new IResourcePolicy Data
{
get
{
return (IResourcePolicy)base.Data;
}
}
protected override void OnUpdate()
{
if(Data != null)
{
Text = base.Data.Name;
if(SubItems.Count == 1)
{
SubItems.Add(((IResourcePolicy)Data).ResourcePolicyEnabled.ToString());
}
Yes it is i am referencing Old DLL ,,what actually happened is i created test application added only relevant forms to test application.So i need to copy the Dll from test application to Original side