Most Correct way to redirect page with Model-View-Presenter Pattern - asp.net

What is the best way to call a Response.Redirect in the Model-View-Presenter pattern while adhering to correct tier separation?

One way I handled this is for the presenter to raise an event (like Succeeded or something) that the view would subscribe to. When the presenter finished it's processing, it would raise the event, which would get handled by the View. In that handler, the view would redirect to the next page.
This way, the presenter doesn't need to know anything about pages or URLs or anything. It just knows when it has completed its task and lets the view know by raising an event. You can raise different events if the presenter succeeded or failed, in case you need to redirect to different places.

I do not know whether it is the most correct way, conceptually.
But what I did in my last MVP-applications, is create a wrapper around HttpContext.Current which I called HttpRedirector.
I also created a dummy redirector for testing purposes. Both keep track of the last redirected url, so that I can check in my unit tests that the redirect actually happened when I call a method on my controller/presenter. With an IOC-container I am able to switch the implementation of IRedirector based on the environment (production/test).

The way we do it works nicely once some ground work is laid. I'm sure there are several ways to skin a cat though. (Who skins cats anyway. Cats are cute and cuddly!)
First, this will only work on the ASP.Net compiled Web Projects, not Websites.
Each page should inherit from a custom abstract base class which looks something like this:
public abstract class PageBase : Page
{
private static string _baseUrl = "/";
public static string BaseUrl
{
get { return _baseUrl; }
set { _baseUrl = value; }
}
protected static string BuildUrl(string basePath)
{
if( !string.IsNullOrEmpty(basePath) && basePath.StartsWith("~/"))
{
basePath = basePath.replace("~/", BaseUrl);
}
return basePath;
}
protected static string LoadView(string path)
{
Response.Redirect(path);
}
}
Each page also implements a page-specific interface. Each page-specific interface also inherits from a base interface:
public interface IPageBase()
{
void LoadView(string path);
}
Then it's a matter of each page defining it's own version of BaseUrl. You might want to account for querystrings/path encryption/etc.
Finally, any of your presenters (which should be referencing the page-specific interfaces) can grab the static BuildUrl() on a desired page to view and then call LoadView() with the returned path.

It depends how generic your presenters are. If your presenters are totally UI agnostic (can be reused between WinForms and WebForms) then you'll have to abstract the redirection operation. In WebForms, the redirection operation would be implemented in the view by a Response.Redirect. In WinForms, (I disclaim lots of experience with WinForms) my guess is that it would be implemented by SomeForm.Show.
One simple, off-the-top-of-my-head option would be to include in the view's interface a ShowViewX() method. You can have one for each form the view could logically redirect to. Alternatively, the view can implement an interface method like Show(ConnectedViews) where ConnectedViews is an enum that includes a value for each of the views that can be "redirected" to from a particular view. This enum would live at the presenter level.
The above approaches are specific to view-presenter pairs. You could instead implement it as a system-wide thing. The logic would be similar to above, implemented in the base view and presenter. There would be a ShowView__() for each form, or a Show(Views) method where Views is an enum of all forms.
It's a toss-up between encapsulation and DRY-ness.

Related

Call another portlet from renderMapping

I want to call another portlet from renderMapping of one portlet. How can i do it. Code snippet is as follows:
Portlet 1:
#RenderMapping
public String handleRenderRequest(RenderRequest request, RenderResponse response, Model model) {
if(!admin){
return "index"
}
else{
//i have to call the rendermapping method of Portlet 2 and need to redirect to portlet 2
}
}
How can i call the portlet 2 .
For maintainability reasons you shouldn't. If both use common code, extract it into a common implementation that both call into. That's the proper way of code reuse. If both portlets are in the same plugin, there will also be no classloading issue and this is a very easy option. Everything else (calling the render method of a totally different portlet) is not your business - leave it purely to the portlet container and don't go there yourself.
As far as I know, you can't. There's a reason why the portlet lifecycle has two phases, the ACTION and the RENDER phase.
If you want to redirect to another portlet, you'll have to use the action phase, so you'll need to create an action URL which can be clicked on, in the action phase you can do something like this:
#ActionMapping("goToDetail")
public void goToDetail(#RequestParam(value = "id") Long id, ActionRequest request, ActionResponse response){
response.setEvent("detailTask", id);
}
In this action phase we set an event, which triggers the portlet wires, so you'll have to configure those properly in your portlet.xml (supported publishing/processing events) and then you probably have to configure something on Liferay as well.

Do all instances of the same ASPX page share the same static field?

Let's consider this page's code-behind:
public partial class Products : Page
{
private static SomeClass SharedField;
public Product()
{
// ... Some logic
}
}
Do all Products pages instances share the same SharedField, I know this is a basic concept of static fields. But in this case, really? all users can have access (and can't have their own instance of) to the same static field on the website-level?
If so, in what aspects this would used by the web developer? or is this non-recommended practice?
Yes, there will be a single instance of that static field for all users, but only within a single worker process. If you have web farms/web gardens, they will each have their own static instance. If the worker process restarts, you'll get a new static instance.
You'll have to use locking around that shared field to ensure thread safety.
As for why to use that, I'm not sure, I never do it. The best example I can give you is the built-in static HttpContext.Current, which gives you access to the Request, Response, etc.
SharedField will be available in one instance for the entire life-cycle of the web site.
To read a bit more about it, see this answer.
A better practice would be to store your object in the Application state.
Application["MyObject"] = new SomeClass();

Unique way to identify page instance within HttpContext

You can get the name of a page within HttpContext via Request.Path.
Is there a way to distinguish between different requests from the same page?
That is when two different instances of yourpage.aspx make a request, how can you distinguish between the two using HttpContext?
you probably want to do this in a base Page class, but here's what i would do
public partial class Default : System.Web.UI.Page
{
private Guid _instanceID;
public Guid InstanceID
{
get { return _instanceID; }
}
/// <summary>
/// Constructor
/// </summary>
public Default()
{
this._instanceID = Guid.NewGuid();
}
}
then using the HttpContext somewhere else in your code...
if (HttpContext.Current.CurrentHandler is Default)
{
((Default)HttpContext.Current.CurrentHandler).InstanceID;
}
Nothing built into ASP.NET will allow you to differentiate different "page instances" or requests from them.
However, you can easily add a Guid to your view state to uniquely identify each page. This mechanism works fine when you are in the Page class itself. If you need to identify requests before you reach the page handler, you need to use a different mechanism (since view state is not yet restored).
The Page.LoadComplete event is a reasonable place to check if a Guid is associated with the page, and if not, create one.
If you're using authentication, would it work for you to distinguish which user submitted the page?
You could use System.Web.Httpcontext.Current.User.Identity.Name.
just throwing this out there: NInject (and other DI containers) use a scoping mechanism based on the HttpContext.Current object itself, so depending on what you're trying to do, you could attempt to retrieve a state object from the DI container and go from there.

What is the best way to reuse pages from one website in another?

I'm developing a new ASP .NET website which is effectively a subset of the pages in another site we've just released. Two or three of the pages will need minor tweaks but nothing significant.
The obvious answer is to simply copy all of the code and markup files into the new project, make the aforementioned tweaks, and consider the job done. However I'm not keen on this at all due to the amount of duplicated code it will create.
My next idea was to move the code for the pages (i.e. the code-behind file) into a separate assembly which can then be referenced from both sites. This is a little awkward however as if you don't take the designer file with it, you get a lot of build errors relating to missing controls. I don't think moving the designer file is a good idea though as this will need to be regenerated each time the markup is altered.
Does anyone have any suggestions for a clean solution to this problem?
You might want to take a look at the MVP pattern. Since you are probably using WebForms it would be hard to migrate to ASP.Net MVC, but you could implement MVP pretty easily into existing apps.
On a basic level you would move all the business logic into a Presenter class that has a View that represents some sort of interface:
public class SomePresenter
{
public ISomeView View{get; set;}
public void InitializeView()
{
//Setup all the stuff on the view the first time
View.Name = //Load from database
View.Orders = //Load from database
}
public void LoadView()
{
//Handle all the stuff that happens each time the view loads
}
public Int32 AddOrder(Order newOrder)
{
//Code to update orders and then update the view
}
}
You would define your interface to hold the atomic types you want to display:
public interface ISomeView
{
String Name {get; set;}
IList<Order> Orders{get; set;}
}
Once those are defined you can now simply implement the interface in your form:
public partial class SomeConcreteView : System.Web.UI.Page, ISomeView
{
public SomePresenter Presenter{get; set;}
public SomeConcreteView()
{
Presenter = new SomePresenter();
//Use the current page as the view instance
Presenter.View = this;
}
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
Presenter.InitializeView();
}
Presenter.LoadView();
}
//Implement your members to bind to actual UI elements
public String Name
{
get{ return lblName.Text; }
set{ lblName.Text = value; }
}
public IList<Order> Orders
{
get{ return (IList<Order>)ordersGrid.DataSource; }
set
{
ordersGrid.DataSource = value;
ordersGrid.DataBind();
}
}
//Respond to UI events and forward them to the presenter
protected virtual void addOrderButton_OnClick(object sender, EventArgs e)
{
Order newOrder = //Get order from UI
Presenter.AddOrder(newOrder);
}
}
As you can see, your code behind is now extremely simple so code duplication is not a big deal. Since the core business logic is all wrapped up in a DLL somewhere, you don't have to worry about functionality getting out of sync. Presenters can be used in multiple views, so you have high reuse, and you are free to change the UI without affecting the business logic as long as you adhere to the contract.
This same pattern can apply to user controls as well, so you can get as modular as you need to. This pattern also opens up the possibility for you to unit test your logic without having to run a browser :)
The patterns and practices group has a nice implementation of this: WCSF
However, you don't have to use their framework to implement this pattern. I know this may look a little daunting at first, but it will solve many of the problems (In my opinion) you are running into.
Create user controls (widgets) or templates to tweak what you want to achieve.
It might also be possible to achieve the same with CSS styles or JavaScript.
Why not create user controls (or custom controls) from the pages which you wish to share? You can then re-use these across both sites.
What we use in our project (JSP, not ASP, but when it comes to building and files it surely isn't an issue?) is to have a base folder of common files, and then another ("instance") folder of additional files and overwrites, and our build script (in ANT, Maven should be fine too) will first copy the base folders, and then based upon a parameter supplied select which instance's files to copy across as well.
Thus we can change a file in the base, and have it apply across all instances.
An issue is that changing a base file will not update any instance file that overwrites it but at least you can make a process for these updates. Presumably you could also use the SVN (etc) revision to flag a build error is an instance file is older than a base file, but we haven't implemented anything that clever yet.
In addition your back-end code (Struts actions in our case) will end up handling all cases rather than any particular instance's cases only. But at least all the code is in one place, and the logic should be clear ("if (instance == FooInstance) { doFooInstanceStuff(...); }").

Implementing a WebControl factory in ASP.NET

I need to implement the classic Factory Method pattern in ASP.NET to create server controls dynamically.
The only way I've found to create .ascx controls is to use the LoadControl method of the Page/UserControl classes. I find it messy however to link my factory with a page or to pass a page parameter to the factory.
Does anybody know of another method to create such controls (such as a static method somewhere i'd have overlooked) ?
Thanks.
In the end, I decided to pass the page as a parameter to the factory. To make calls to the factory method easier, I changed the factory class from a singleton to a common class, and I passed the page to the constructor:
public ControlsFactory
{
private Page _containingPage;
public ControlsFactory(Page containingPage)
{
_containingPage = containingPage;
}
public CustomControlClass GetControl(string type)
{
... snip ...
CustomControlClass result = (CustomControlClass)_containingPage.LoadControl(controlLocation);
return result;
}
}
Since I have to instantiate many controls on each page with the factory, this is probably the most concise and usable way to implement the pattern.
Well after opening up reflector, the LoadControl function that is being used in Page is available in any TemplateControl.
Inside the actual LoadControl uses internal methods in BuildManager, so I don't think there's a way to use static methods without using reflection.
Well at least you don't need to pass a page around. Subclassing TemplateControl would work.

Resources