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?
-
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.
-
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.
-
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(...); }").
-
You might want to take a look at the MVP pattern. Since you are probably using WinForms 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.
0 comments:
Post a Comment