ASP.Net C# - Moving Code from Codebehind to Class File - c#

For some time now I am trying to figure out how I can refactor some of my code to reduce redundancy throughout my application. I am just learning the basics of OOP and can create simple classes and methods but my knowledge is limited in terms of practical applicability. The following bit of code illustrates my frustration:
#region DELETE selected users - button
protected void btnDeleteSelected_Click(object sender, EventArgs e)
{
try
{
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox cb = (CheckBox)row.FindControl("chkRows");
if (cb != null && cb.Checked)
{
// get the row index values (DataKeyNames) and assign them to variable
string userName = GridView1.DataKeys[row.RowIndex].Value.ToString();
// delete selected users and their profiles
ProfileManager.DeleteProfile(userName);
Membership.DeleteUser(userName);
Msg.Text = "User(s) were sucessfully <b>DELETED</b>!";
Msg.Visible = true;
}
}
}
catch (Exception ex)
{
Msg.Text = "Oops! " + ex.Message;
Msg.Visible = true;
}
finally
{
// refresh gridview to reflect changes
GridView1.DataBind();
}
}
#endregion
This bit of code is used on several pages of my project in the pages codebehind file. How can I move this to a class file. I don't know how to reference an object like a gridview in a class because it does not exist like it does on the actual page.
Could some one help out please? Thank you.

There are many principles that you generally apply when trying to refactor code. Currently, you're trying to refactor your code as to not violoate the DRY principle (DRY = don't repeat yourself). It would be a great move to refactor that code.
But, some other principals might come in to play that you might want to consider. The single responsibility principle would suggest that each method does only one unambiguous thing. Think about the operations your current method does. It extracts the usernames from the GridView, and then deletes some data associated with that user. That might be better off as two methods.
Also, loosely coupled code is good. You don't want a bunch of dependencies between your classes. For example, if you moved your whole method, as is, to a separate class or library, that class or library would be dependent on the ASP.NET libraries, because it makes a specific reference to the GridView control. But it doesn't need to. You could have a separate method that pulls the username out of the GridView (this method would be tightly coupled with ASP.NET), and then a separate one that does the rest of your actions (such as deleting the user's data), which only requires the username. That second method would not be coupled to ASP.NET in any way. So by having separate methods that each have a single responsibility, you'll have more loosely coupled code. Two for one.
As for what you said here:
I don't know how to reference an
object like a gridview in a class
because it does not exist like it does
on the actual page.
You'd just want to pass a reference to your GridView when you call the method that would extract the usernames. Something like this:
public static class Util
{
public static IEnumerable<string> GetUsernames(GridView gv)
{
List<string> userNames = new List<string>();
foreach (GridViewRow row in gv.Rows)
{
CheckBox cb = (CheckBox)row.FindControl("chkRows");
if (cb != null && cb.Checked)
{
// get the row index values (DataKeyNames) and assign them to variable
string userName = gv.DataKeys[row.RowIndex].Value.ToString();
userNames.Add(userName);
}
}
return userNames;
}
}
Now, in any of your asp.net code behind pages, you can do:
IEnumerable<string> usernames = Util.GetUsernames(GridView1);
foreach(string username in usernames)
doSomething(username);
The doSomething(username) would be a call to some other method that does your delete operations, or whatever you want.
Hope this helps.
Oh, and if you're just learning the basics of OOP, I would recommend something like Head First Object-Oriented Analysis and Design, or any book that seems to adequately cover the subject. I like the O'Reilly Head First series. The information is very digestible.

In Webforms applications, a common technique for factoring out application and/or business logic out of the code behind is to use the MVP pattern. This doesn't mean all the code typically found in the code-behind just gets moved to another class, as this really isn't any different than a code-behind. The UI rendering logic (e.g. Databinding setup, access to UI controls, etc.) is best left to the code-behind, but the business logic (in this case, the removal of users) is performed by a method within the Presenter.
In your case, I would build up a collection of usernames and call a RemoveUsers() method on the Presenter, passing in the list of usernames, which would handle interfacing with the ProfileManager and Membership components(ideally through abstractions). This allows you to write unit tests for the logic within the Presenter.

Related

Complex WPF UserControl in MVVM application

Having taken over maintenance of an existing WPF application, I was horrified to discover that two of the Views and ViewModels had large blocks of near-identical code. Obviously, I want to refactor this so they can both reuse a single block of functionality, but I'm not sure how best to go about it, architecturally.
The identikit code deals with processing UI data from a tab. However I split this, it is essential that the code in the other tabs (which is different in the two cases) has access to the properties and objects of the tab I need to split out.
To further complicate matters, the replicated code needs database access. We've got a repository object that handles this. Normally when creating new objects, I've been making them testable by passing a copy of the repository into the constructor. However, if I do that in this case I'll have two copies of the repository object - one in the ViewModel, one in the split out code - needing to handle the same data, which is going to cause concurrency issues.
My first thought was to make a UserControl for this, but the more I think about this, the more problematic the two issues above seem to be.
The other option I've considered is just to make a Helper class to do some of the identical processing. But that's only going to partially solve the problem as some identical UI code (raising property changed events, XAML, etc) is still going to be in both Views/ViewModels.
What's the best approach here? Is there a way I can get past the repository/access issues and make a UserControl? Or is than an alternative based on Interfaces or Inheritance I haven't considered?
EDIT - Code was asked for. It's a bit complex to give a comprehensive example, but here's a snippet from each VM:
public void CheckOrderHist(int months)
{
var endDate = DateTime.Today.AddMonths(months);
Dictionary<OrderHistory, bool> orders = new Dictionary<OrderHistory, bool>();
this.ordersToExclude.Clear();
foreach (var kvp in rep.OrderHistories.GetRecent(months))
{
if (kvp.Key.MailingDate >= endDate)
{
orders.Add(kvp.Key, true);
this.ordersToExclude.Add(((OrderHistory)kvp.Key).OrderID);
}
else
{
orders.Add(kvp.Key, false);
}
}
BuildOrderExclusionsOnCount(); //code in this is near-identical across VM's too
OrderHistoryMonths = Math.Abs(months); //OrderHistoryMonths is a property on the ViewModel
OnPropertyChanged("MajorityOrderBoolean");
}
And in the other VM:
private void CheckOrderHist(int months)
{
var endDate = DateTime.Today.AddMonths(-months);
ObservableCollection<Tuple<OrderHistory, bool>> orders = new ObservableCollection<Tuple<OrderHistory, bool>>();
this.ordersToExclude.Clear();
foreach (var tuple in rep.OrderHistories.GetRecent(-months))
{
if (tuple.Item1.MailingDate >= endDate)
{
orders.Add(new Tuple<OrderHistory,bool>(tuple.Item1, true));
this.ordersToExclude.Add(tuple.Item1.OrderID);
}
else
{
orders.Add(new Tuple<OrderHistory, bool>(tuple.Item1, false));
}
}
BuildOrderExclusionsOnCount(); //code in this is near-identical across VM's too
OrderHistoryMonths = months; //OrderHistoryMonths is a property on the ViewModel
OnPropertyChanged("OrderHistories");
OnPropertyChanged("GroupedOrders");
}
This illustrates the problem nicely - the function is essentially the same, but one uses a Dictionary and the other a Tuple (there's no good reason for this - they both need a Tuple really, for ease of ordering). And one arbitrarily takes a negative int parameter, and the other a positive.
Both contain different OnPropertyChanged events, and will use different copies of the repository object, making it hard to properly separate them using a Helper class. Yet putting it in a UserControl would isolate them from OrderHistoryMonths on the main ViewModel.
If I'm hearing the current comments right, the best solution here is to farm out the main ForEach loop to a helper class, and just put up with the rest of the duplication?
By all means, extract common logic where possible to a new 'helper' class that each ViewModel can construct; this is the standard pattern of re-use through composition. The code you've shown in your question is a good candidate for this kind of refactoring.
As far as boilerplate, though, it's a bit trickier. This is something that is difficult to address in general and must be examined on a case-by-case basis. There are various ways to simplify property changed notification, for instance (helper methods encapsulating property updates, AOP, etc.) but these are generally part of your MVVM framework and embraced application-wide. As far as XAML duplication, you can often use Styles, Data Templates and Value Converters to improve things, but again, it requires a careful analysis of your particular code base to identify the patterns that may merit this treatment. If you have more specific examples that you think are clear duplicates, but aren't sure how to refactor, those may make good questions.

Winforms method/event filter attribute

I have been working with ASP.NET MVC for over a year now. I love ASP.NET MVC. In the meantime, every now and then I develop a Windows Forms Application. This application allows our customers to create a group structure for their webshop.
For that purpose I use a TreeView. How does this relate to ASP.NET MVC? Well, MVC has these action filter attributes that come in quite handy and makes the code better readable (in my opinion). I mean filters like for example the [Authorize] attribute, which stops the action from executing if the user is not authorized.
So the actual question is, can a simular filter be created for the methods and events in a Windows Forms Application? I need to check (in a lot of methods and events) if the SelectedNode property of the TreeView has a value. Now I do that this way:
private void setSelectedGroupInformation(bool refreshProductCount)
{
GroupNode selectedNode = trvGroupTree.SelectedNode;
if (selectedNode == null || !selectedNode.HasGroup)
return;
// Code that actually DOES something
}
But it would be nice if this would be possible:
[SelectedNodeRequired]
[GroupRequired]
private void setSelectedGroupInformation(bool refreshProductCount)
{
// Code that actually DOES something
}
That is much better readable. I checked out the internet for this but I can't find a similar question.
It might be nice, but you need to do some work for it (one example, is constructing a type at runtime). What is relatively easy to do is to call some common method at first
[SelectedNodeRequired]
[GroupRequired]
private void setSelectedGroupInformation(bool refreshProductCount)
{
if(MethodTester())
return;
// Code that actually DOES something
}
bool MethodTester()
{
// use call stack to get caller method name
// use reflection to get attributes of method
// check attributes and conditions
...
return true; // if has to be filtered
...
return false;
}
But, why not making methods what actually does all logic you need to check? Like this
private void setSelectedGroupInformation(bool refreshProductCount)
{
if(Global.IsGroupRequired && Global.IsSelectedNodeRequired)
{
// Code that actually DOES something
}
}

WPF: property similar to WinForms Modified

In WinForms controls like a TextBox have property Modified that gets value "true" after changing the control's content and may be set to "false" manually. Their WPF analogues seem not to have such property (neither IsModified in new naming style). So do I have to handle their modifying events myself or there's some more convenient way?
For example I have few textboxes and a function, which combines their contents into one document for preview. Opening the preview I want to keep an old content for the document, if none of the textboxes was changed or to call the function to produce new document's content if at least one textbox was edited.
In WPF it's easier to control everything through ViewModel/Model... This might be too much/not what you're looking for. But through experience, I feel that the pattern below pays off in easy usage.
Wrap your simple data class (with all the properties that it is using now/in your question now) in a class/Model that implements IEditableObject, INotifyPropertyChanged and possibly IEquitable. Lets call your class Data.
In a wrapper class create fields:
Data _current;
Data _proposed;
Data _previous;
IEditableObject requires you to implement BeginEdit(), EndEdit() and CancelEdit().
in them you need to control the state _current, proposed, and previous. For example,
public void CancelEdit()
{
_current = _previous;
_proposed = null;
}
public void EndEdit()
{
_previous = _proposed;
}
public void BeginEdit()
{
_proposed = _current;
}
You might need more logic in methods above, so this is just an example. The key of knowing if your object has changes is implementing a flag, lot's of people call it IsDirty:
pubic bool IsDirty { get { return _current != _previous; } }
Now the user of this class can easily check the state. Oh, and on more thing each property would have the following mechanism:
public string Example
{
get { return _current.Example;}}
set
{
if(_current.Example == value) return;
BeginEdit();
_current.Example = value;
RaisePropertyChanged (() -> Example);
}
}
What's nice about implementing IEditableObject, all controls respond to it, DataGrid is a good example and also you can easily return to the original state by cancelling edit.
Anyway, there are lots of samples that you should browse for. I just hope to can get you started onto that path...
P.S. this pattern was used before WPF came out, its super common in WinForms as well
WPF doesn't have that because UI is not Data and therefore your UI is not the right place to store information about whether your data has changed or not.
Crappy dinosaur winforms doesn't allow a clean and true separation between UI and application logic/data and therefore has all sorts of horrible hacks in order to mash together these completely separate concepts.
You must learn to develop correctly, using the MVVM pattern. Then you will realize there's no sense in placing state data on any UI elements.

Ways to share common functions betweed few pages in ASP.NET

This is possibly very lame question and I lack knowledge about ASP.Net. In this case a link to an article explaining would be very welcome.
I'm working on web-site on ASP.NET with C# as codebehind. My current project involves developing few pages with very similar functionality and a many functions are the same. For example
private void PermissionCheck()
{
if (null == Session["UserID"] ||
null == Session["ProjectID"] ||
null == Session["AssetID"] ||
null == Session["ProjectName"])
{
Response.Redirect("~/Login.aspx");
}
}
Would be the same on 2 pages. Some other things are the same as well. I would like to put this into common base class. But there are other functions that don't really belong to pages at all:
private string GetAttachmentTempPath()
{
return Request.PhysicalApplicationPath + WebConfigurationManager.AppSettings.Get("AttachmentsTempFolder");
}
I would like to move this into Attachment class, but to get the physical path of the application, I need to pass in Request object into that method, which is not really nice, as it couples Attachment class with Page.Request object.
Is there any way to move these functions somewhere else without needing to pass Page.Request objects around??
p.s. The appliction is huge, and there is no scope to change the entire architecture.
For your permission thing you could make a base page class:
class BasePage : Page
{
...
protected override OnInit() {
// do check here
}
}
Now you can implement your page like this class MyOtherPage : BasePage { ... }
The OnInit gets executed everytime your MyOtherPage gets loaded.
You can see a complete page lifecycle here: Link
For your other problem: Consider to implement a global available static tool class
Update
A good approach for making things like web.config easier to access is a Singleton. In asp.net a singleton is only created once and lives until the asp worker process gets stopped . So this values are shared across the whole asp.net application. This is also good for storing data in a global context that you dont want to get out of your database or file anytime a user makes a page request (for example a version number or things like that)
Update 2
To access the request without passing it to every function, use this:
HttpContext.Current.Request
Base page is a good option for reusable code in Page level. Other than that for things like configuration values it's good to come up with utility classes specifically for those methods base don there type of operations.
If you need to avoid passing in Page object into these types of utility methods,
HttpContext
class would be handy because you can access many of the ASP.Net object through static members through this class. HttpConext # MSDN
If you have similar functions behind the page, you can use ASP.NET WEb User Control.
You can create the functions in the usercontrol and use the control in the pages where necessary.
Have look at this article about Web User Control in Asp.Net

ASP C# How to program neat GUI code

For about a few months i'm programming ASP C#. I always program a lot code in the events and in the load event i check the querystring for valid data. This is some sample code i have in one of my projects:
protected void Page_Load(object sender, EventArgs e)
{
if (Controller.Manual == null)
{
Response.Redirect("login.aspx");
}
lblLocation.Text = "<a href='viewdocument.aspx'>" + Controller.Manual.Title + "</a>";
if (Request.QueryString["gchap"] != null)
{
if (Controller.IsNumeric(Request.QueryString["gchap"].ToString()))
{
genchap = Convert.ToInt32(Request.QueryString["gchap"]);
FillGeneralList();
SetChapterTitle();
}
}
if (Request.QueryString["qchap"] != null)
{
if (Controller.IsNumeric(Request.QueryString["qchap"].ToString()))
{
qualchap = Convert.ToInt32(Request.QueryString["qchap"]);
FillQualityList();
SetChapterTitle();
}
}
// Check document Id is set (did)
if (Request.QueryString["did"] != null)
{
if (Controller.IsNumeric(Request.QueryString["did"].ToString()))
{
docId = Convert.ToInt32(Request.QueryString["did"]);
DetermineView();
}
}
}
I know there must be a way to accomplish this on a more neat way. And this is just the load event. On other events, like click and onchange events i have similar code. I think this is spaghetti code and not well-arranged. So can you tell me how i can arrange my code?
EDIT:
What i want to know is, is there a more neat way to, let's say, fill a listbox? And where do i check whether a querystring value has valid data? Where do i check whether the (input/querystring) data is a number? And where should you put the code that validates the Querystring? Also in the load event?
I feel your pain with some of the organization issues with ASP.NET websites. I've had similar code to yours on several projects.
If you have the choice of your frameworks you might look into ASP.NET MVC. This allows you to have clear separation between the View (Html), the Controllers (All actions and business logic) and the Model (database). That way you have zero code in your codebehind files, it all stays nice and neat in controllers.
Try using TryParse (for example) and you can simplify all the code that looks like
xx.IsNumeric(Request.QueryString["qchap"].ToString())
and
Convert.ToInt32(Request.QueryString["gchap"]);
and reduce the number of calls to Request.QueryString variables
You could try something like
Original code
if (Request.QueryString["gchap"] != null)
{
if (Controller.IsNumeric(Request.QueryString["gchap"].ToString()))
{
gchap = Convert.ToInt32(Request.QueryString["gchap"]);
FillGeneralList();
SetChapterTitle();
}
}
Suggestion
int? gchap; //nullable types thanks Richard :D
if (!int.TryParse(Request.QueryString["gchap"], out id)) {gchap = null};
if (gchap != null) {
FillGeneralList();
SetChapterTitle();
}
// you could make this neater with your own little method
Have a look at this post How do you test your Request.QueryString[] variables?
Try capturing the repetitive code in a separate function. (qchap / gchap)
e.g.:
qualchap = ConvertFillAndSet(Request.Querystring["qchap"]);
genchap = ConvertFillAndSet(Request.QueryString["gchap"]);
private int ConvertFillAndSet(string qrystring)
{
int numberToReturn = 0;
//if the conversion was ok -> true, else false
if (Int32.TryParse(qrystring,numberToReturn))
{
FillQualityList();
SetChapterTitle();
}
//returns 0 if tryparse didn't work
return numberToReturn;
}
Where to start. Unfortunately despite other comments, you're not really writing anything that is 'web forms' specific. So moving to MVC isn't going to magically make your code better.
1 Don't roll your own authentication: Use forms authentication unless you have a compelling reason not to. When using forms authentication, you don't need to write code on every page to check that you're logged in. The framework handles that for you.
2 Learn to use the server controls:
Also as others write you shouldn't be writing html in code, especially for something so trivial. Web forms doesn't make you do this either.
<!-- this is in MyPage.aspx -->
<asp:HyperLink id="viewLink" runat="server" />
// in the code-behind file MyPage.aspx.cs
viewLink.NavigateUrl = "~/viewdocument.aspx";
viewLink.Text = Controller.Title;
If you're going to stick with web forms, you need to get familiar with the ASP.Net Page life-cycle
3 Your code is in need of refactoring. No matter if it's web forms, php, or MVC. Here are some basic refactorings, and none of this is really .net specific. I'll walk through these in small steps.
// this may be a good candidate for an extension method
int? ConvertNullable(string nullableInt) {
if( string.IsNullOrEmpty(nullableInt) )
return null;
int value;
if( Int32.TryParse(nullableInt, out value) )
return value;
return null;
}
which then allows you to write.
int genchap? = ConvertNullable(Request.QueryString["gchap"]);
int qualchap? = ConvertNullable(Request.QueryString["qualchap"]);
int docId? = ConvertNullable(Request.QueryString["did"]);
FillQualityList(genchap,qualchap);
SetChapterTitle(genchap,qualchap);
DetermineView(docId);
but passing a lot of primitives around is a hassle and prone to errors, so sometimes we make a small class to encapsulate the data, in this case the page initialization information.
class ChapterView
{
public int? GenChapter {get; set;}
public int? QualChapter {get; set;}
public int? DocumentId {get; set;}
}
private ChapterView GetChapterView()
{
return new ChapterView
{
GenChapter = ConvertNullable(Request.QueryString["gchap"]),
QualChapter = ConvertNullable(Request.QueryString["qualchap"]),
DocumentId = ConvertNullable(Request.QueryString["did"])
}
}
Note that I've no idea what GenChap and QualChap are, but they're a bit terse and you could complete the refactoring to make them more readable in code. But even without better names, we now have more readable code.
ChapterView chapterView = GetChapterView();
FillQualityList(chapterView);
SetChapterTitle(chapterView);
DetermineView(chapterView);
And finally you may determine that you don't really need to call this every time the page executes to read from the query string. If you've read up on the Asp.Net Page LifeCycle you know that events may change GenChapter or something else that affects how the page is rendered. You may find it better to set up the view in the PreRender instead of calling FillQualityList over and over again.
ChapterView chapterView;
Page_Load()
{
if( !IsPostback )
{
ChapterView chapterView = GetChapterView();
}
else
{
chapterView = (ChapterView) ViewState["chapterview"];
}
}
NextChapter_Click()
{
chaperView.NextChapter();
}
Page_PreRender()
{
FillQualityList(chapterView);
SetChapterTitle(chapterView);
DetermineView(chapterView);}
// make sure class is marked [Serializable]
ViewState["chapterview"] = chapterView;
}
you should follow layered approach. ie: put all your data access code in data access layer, put all your business logic (which also includes validations) in your business layer, put all your model code in your business object layer
and finally for ui - try to never generate html mark up from within the code as far as possible. also, always create a root class for your aspx pages where it has common methods already implemented. then subclass this root class for every other aspx pages
if you are going to hardcode html markup within your c# code - i can assure you this would always result in a lot of chaos (based on my own experience)
but there are situations where you simply cant avoid it. for such cases - this is what i do - i get rid of the code behind and simply put that code in my aspx / ascx file itself. that way when i have to change my ui based on never ending client requests, i dont have to recompile my code - i simply replace my aspx / ascx files on the staging / production server.
you know how clients are : hmmm can u make the black strip look a bit like gray, can u increase the spacing between lines, can u change the text of this hyper link... requests like these never seem to end :-)

Categories