Sunday, May 22, 2011

Contact Form Revisited with ASP.NET MVC 3, jQuery Validator, & the jQuery Form Plugin




I recently added a partial contact view to my MVC3 project and thought I’d share since I did basically this same post over a year ago with the original MVC. I stopped using the Castle Validation because I’ve found that the MVC3 stuff is working for me now. I also am not using fluentHtml anymore because MVC3 uses that style now.

Okay…let’s get started.

We’ll start with the view model class like the last post. By the way, if you’re not familiar with the way I setup my MVC projects, see this post. (If you read my first Contact Form post, you’re probably experiencing déjà vu).

public class ContactView
{
[Required]
public string Name { get; set; }
[Required, ValidateEmail(ErrorMessage = "Valid email is required.")]
public string Email { get; set; }
[Required]
public string Subject { get; set; }
[Required]
public string Message { get; set; }
}

The Required attribute is exactly what it seems like and it’s part of the System.ComponentModel.DataAnnotations. The default error message is “The [propertyname] is required.”. If you want to reset it, you can do this: [Required(ErrorMessage = “Whatever I want it to be”)].

The ValidateEmail is a custom validation attribute. I didn’t like the looks of having a RegularExpressionAttribute defined there and since email is such a common thing to validate, I made this one:

public class ValidateEmailAttribute : RegularExpressionAttribute
{
public ValidateEmailAttribute(): base(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
{
}
}

It just inherits from the RegularExpressionAttribute and passes in the regex to validate an email address. Apparently there is much discussion on how to validate an email address, which I believe is why Microsoft didn’t provide this to us.

So let’s look at the View/XHTML Markup.

@model Sample.Core.UI.Model.ContactView
@using Sample.Core.UI.Helpers
@using (Html.BeginForm("Contact", "Home", FormMethod.Post, new { id = "contactform" }))
{
<fieldset>
<legend>Contact Us</legend>
    <p>
@Html.LabelFor(f => f.Name, "Your Name")<br />
@Html.TextBoxFor(f => f.Name, new { style = "width: 200px", @class="required", accesskey="n" })
</p>
<p>
@Html.LabelFor(f => f.Email, "Your Email")<br />
@Html.TextBoxFor(f => f.Email, new { style = "width: 200px", accesskey = "e" })
</p>
<p>
@Html.LabelFor(f => f.Subject, "Subject")<br />
@Html.TextBoxFor(f => f.Subject, new { style = "width: 200px", accesskey = "p" })
</p>
    <p>
@Html.LabelFor(f => f.Message, "Message")<br />
@Html.TextAreaFor(f => f.Message, new { style = "width: 350px", rows = "4", accesskey = "c" })
</p>
@Html.AntiForgeryToken()
<input type="submit" id="bContact" name="bContact" value="Send Message" accesskey="s" /> 
@Html.DivSuccessMessage("Message sent successfully", "contactsuccess") 
@Html.ValidationSummary("", new { id = "contacterror" })
<noscript><br /><br /><div class="tip">Our contact form may look and act funny because you have JavaScript disabled. For a better experience on thissample.com, please enable JavaScript.</div></noscript>
</fieldset>
}

You can see at the top of the page I specify my view model. I ‘m also referencing a helper namespace for my DivSuccessMessage extension. Basically all it does is checks the ModelState for errors and for ViewData[“success”] not being null and displays the message specified. After that it’s basically a plain ole HTML form.

Okay, now we have our form built with our view model. Below the end of the XHTML above, I have the following jQuery code.

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.8/jquery.validate.min.js"></script>
<script type="text/javascript" src="http://www.malsup.com/jquery/form/jquery.form.js"></script><script language="javascript" type="text/javascript">
$(document).ready(function () {
var formoptions = { beforeSubmit: function (formData, jqForm, options) {
$("#bContact").attr('value', 'sending...');
$("#bContact").attr('disabled', 'disabled');
}, success: function (data) {
if (data.status == "Success") {
$("#contacterror").hide();
showMessage("#contactsuccess", data.message);
$('.valid').removeClass('valid');
validator.resetForm();
}
else {
$("#contactsuccess").hide();
showMessage("#contacterror", data.message);
}
$("#bContact").attr('value', 'Send Message');
$("#bContact").removeAttr('disabled');
}, dataType: "json"
};jQuery.validator.messages.required = "";
var validator = $("#contactform").validate({
submitHandler: function (form) {
$(form).ajaxSubmit(formoptions);
},
invalidHandler: function (e, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
var message = errors == 1 ? 'You missed 1 field. It has been highlighted.' : 'You missed ' + errors + ' fields.  They have been highlighted.';
showMessage("#contacterror", message);
$("#contactsuccess").hide();
} else {
$("#contacterror").hide();
}
},
messages: { Email: { email: ""} },
rules: {
Subject: "required",
Message: "required",
Email: { required: true, email: true }
},
errorClass: "invalid",
validClass: "valid",
errorContainer: "#contacterror"
});function showMessage(id, message) {
$(id).html(message);
$(id).show();
}
});
</script>

Let’s break this down. First section the formOptions:

var formoptions = { beforeSubmit: function (formData, jqForm, options) {
$("#bContact").attr('value', 'sending...');
$("#bContact").attr('disabled', 'disabled');
}, success: function (data) {
if (data.status == "Success") {
$("#contacterror").hide();
showMessage("#contactsuccess", data.message);
$('.valid').removeClass('valid');
validator.resetForm();
}
else {
$("#contactsuccess").hide();
showMessage("#contacterror", data.message);
}
$("#bContact").attr('value', 'Send Message');
$("#bContact").removeAttr('disabled');
}, dataType: "json"
};

This code is used to define all my options for the jQuery.Form plugin. What it says is this:

  • beforeSubmit – Change the button to say “sending…” and disable it
  • on success – if the status = “Success” then hide the contacterror div, show the success message, manually remove the valid class from my inputs, and reset the form. Otherwise, hide the success message and show the error message with the message received. Regardless, re-enable my button and make it say “Send Message”. (Note: I shouldn’t have to manually remove the valid class, but the resetForm wouldn’t do it for me like it’s supposed to do.)
  • dataType – json received from my action

The validation section:

jQuery.validator.messages.required = "";
var validator = $("#contactform").validate({
submitHandler: function (form) {
$(form).ajaxSubmit(formoptions);
},
invalidHandler: function (e, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
var message = errors == 1 ? 'You missed 1 field. It has been highlighted.' : 'You missed ' + errors + ' fields.  They have been highlighted.';
showMessage("#contacterror", message);
$("#contactsuccess").hide();
} else {
$("#contacterror").hide();
}
},
messages: { Email: { email: ""} },
rules: {
Subject: "required",
Message: "required",
Email: { required: true, email: true }
},
errorClass: "invalid",
validClass: "valid",
errorContainer: "#contacterror"
});

This code defines my validation for the contact form. It says this:

  • Set all messages for required fields to empty by default
  • submitHandler – on submit do this, which it calls the ajaxSubmit contained in the jQuery.Form plugin with our options specified above.
  • invalidHandler – if the form isn’t valid, get the number of errors and show the error message. Otherwise, hide the error message.
  • messages – Defines what the message should be for email, which is empty. I would’ve had to specify the required messages too had I not set them to empty first. Also note that the Email: has to match the ID of one of  your inputs.
    • Example: <input type=”text” id=”whateverid”/> so the messages would looks like this:

      messages: {whateverid: {required: “some message”}}

  • rules – Defines the rules for each input. Phone, Comments are required and Email has required and email. Notice name is required, but not specified here. It’s because I added the required class to the Name input in the XHTML instead of specifying down here so you could see you have options.
  • errorClass – Specifies my style class for when the input is invalid.
  • validClass – Specifies my style class for when the input is valid.
  • errorContainer – Specifies the div I want to show my error messages in.

Final section:

function showMessage(id, message) {
$(id).html(message);
$(id).show();
}

This just finds the container sets the html and shows it.

Okay, so finally here’s what the controller looks like that we mentioned in the @Html.BeginForm() section above.

[HttpPost, ValidateAntiForgeryToken, ValidateInput(true)]
public ActionResult Contact(ContactView view)
{
if (!ModelState.IsValid)
{
if (Request.IsAjaxRequest())
return Json(new { status = "error", message = "All fields are required." });

return View(view);
}    try
{
var notificationService = DI.EmailNotificationService(new EmailNotification(view));
notificationService.Notify();
}
catch (NotificationException)
{
ModelState.AddModelError("notifyerror", "Could not connect to mail server.");
}    if (Request.IsAjaxRequest())
return ModelState.IsValid ? Json(new {status = "Success", message = "Message sent successfully."}) : Json(new {status = "error", message = "Could not connect to mail server."});    return ModelState.IsValid ? Success(view) : View(view);
}

So this action accepts HttpPost, must have a valid Anti-Forgery Token, and it validates the input. First thing it does is verifies the modelstate is valid. The reason for this is that some people run their browser with JavaScript disabled. So we have to account for that in our code and make sure that we are validating on the client-side and on the server-side. So if the ModelState is invalid, we have to check to see if it’s an AJAX request. if it is, we return a Json result with the status of error and a message stating all fields are required. If it’s not an AJAX request, we simply return the view.

If all is valid, we continue and go ahead and send the notification. If the notification bombs, we add an error to the modelstate and then recheck and act accordingly. If you want to know what the notification service looks like, please refer to the first post because it’s all the exact same.

So, this method of coding will work when JavaScript is enabled and disabled and all the data will be validated regardless as well.

Here’s what the screen looks like after just hitting Send Message:

image

Here’s what it looks like after all the fields are valid right before I hit Send Message:

image

After message sent:

image

Please let me know if you have any questions.

Download Demo

Thanks for reading!

Shout it

kick it on DotNetKicks.com

Monday, May 09, 2011

Seriously WebForms like ASP.NET MVC




I used my little WebFormContrib library again today. Some days I love revisiting old code because you realize how ignorant of some practices you were in the past. Hopefully none of you download it and say…geez this guy is Mr. Ignoramus. If you do, keep it to yourself. Kidding, please comment and inform the ignorant (me).

Anyhow, it’s been about 6 months since I’ve had to use WebForms, but today I had to and it wasn’t bad. I was able to tie my view into my pages and controls and used AutoMapper to map back to the domain from it. To me, WebFormContrib makes WebForms kinda fun again…cause it makes it seem new. I really do think it’s a great stepping stone to using MVC just because you kinda get used to the syntax. I also think it’s a decent library because I didn’t have to go relearn how it worked, I just referenced the library and then started working on my little WebForm app. I set it up just like I do my MVC apps. I also had to add a couple things and it was easily extendable, which I’m sure you all know is a good thing.

Anyhow, if you have no idea what I’m talking about, please read my previous posts on WebFormContrib.

Also, how could I post without a code sample? In “The Original” post, I mentioned the first thing I wanted to refactor was the validation section. Well, I did. Here’s the new and improved ModelIsValid() method:

        internal bool ModelIsValid(TModel view)
{
ErrorMessages =
new List<string>();
foreach (var property in typeof(TModel).GetProperties())
{
var value = property.GetValue(view, null);

var attributes = property.GetCustomAttributes(typeof(IValidationAttribute), false);
foreach (IValidationAttribute valatt in attributes)
if (!valatt.IsValid(value))
ErrorMessages.Add(valatt.Message);
}

return ErrorMessages.Count == 0;
}

Previously, it looked like this:

        internal bool ModelIsValid(TModel view)
{
ErrorMessages =
new List<string>();
foreach (var property in typeof(TModel).GetProperties())
{
var attributes = property.GetCustomAttributes(typeof(RequiredAttribute), false);
if (attributes.Length > 0)
{
var value = property.GetValue(view, null);
if (value.ToSafeString() == string.Empty)
ErrorMessages.Add(((
RequiredAttribute)attributes[0]).Message);
}
}

if (ErrorMessages.Count == 0)
return true;

return false;
}

Obviously…I was a moron. I still don’t think it’s perfect, but it is a serious improvement. It’s funny how you don’t see how to refactor something until you need to extend it. As soon as I created the length validator and added the code here I thought…wow this is dumb and then OH! do it this way. Anyhow, I thought I’d share the slight improvement.

You can download the source and samples here…or just download the DLL here.

Thanks for reading!

Shout it

kick it on DotNetKicks.com

Friday, April 15, 2011

ASP.NET MVC 3 Sample Project Launched




Okay, after popular demand of I think 0 people, I’ve published my old demo MVC 1 project as an MVC 3 project. If you haven’t read any of the posts on the last demo project, check out this post. This project completely separates UI & C# code, so you only have 2 projects (Core & UI…not counting the Unit Tests project).

Basically, all I did was create a new MVC 3 project using Razor with Microsoft’s default template and deleted everything except the following:

  • Views folder
  • Root Default.aspx
  • global.asax (I did delete the global.asax.cs)
  • both web.configs

I referenced my Core, setup my views that match my Core project, and inherited from my global.cs in the global.asax. That was it!

You can download it via zip here: http://code.google.com/p/derans/downloads/list (the file is called DemoPhotographySite_v3.zip)

I feel like this project will act as a great stepping stone to understanding the Code Camp server, which is much more complex.

The sample project was built with the following tools:

If you downloaded the old one, you’ll notice that I removed the following 3rd parties:

The primary reason I removed these three parties is because MVC 3 and Razor are good enough so you don’t need the 3rd party tools.

The best practices I mentioned above come straight from experience and the following people/resources:

You can see the exact same Core code in use at sweetandhappy.com. If you see any improvements that can be made or you’d just like to comment, please do so!

Also, please note that I basically am even re-posting the exact same blog post I did over a year ago with my original MVC demo project. I hope you don’t mind, but it’s late and I have to work tomorrow :)

Thanks for reading!

Shout it

kick it on DotNetKicks.com

Sunday, March 20, 2011

Simplify Authorization with an Attribute




There are about 10 bajillion ways to figure out if a user is authorized to call a method or see a page or whatever else. This particular post is about how to create an attribute to see if a user is authorized to do a particular action. I’ll give an example using MVC and WebForms.

For MVC, you’d create a filter attribute and override the OnActionExecuting method like this:

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class AllowAttribute : ActionFilterAttribute
{
private readonly string[] _allowedRoles;

public AllowAttribute(params string[] allowedRoles)
{
_allowedRoles = allowedRoles;
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//if (authorized)
//return

filterContext.Controller.ViewData.ModelState.AddModelError("AccessDenied", "Access denied");
throw new AccessDeniedException();
}
}

The commented out part is where you’d actually call your authorization service or however you want to go about authorizing a user. I’m accepting the roles allowed for the particular method in the constructor. Here’s the AccessDeniedException:

    public class AccessDeniedException : BaseHttpException
{
public AccessDeniedException() : base((int)HttpStatusCode.Unauthorized, "User not authorized.") { }
}

public class BaseHttpException : HttpException
{
public BaseHttpException(int httpCode, string message) : base(httpCode, message) { }
}

So on the controller action, it’d look something like this:

        [Allow(Roles.Administrator, Roles.OtherSampleRole)]
public ActionResult SampleAction()
{
return RedirectToAction("SampleAction");
}

Since I hate risking mistyping something, I’ll typically setup an enum or a class with consts…something like this:

    public class Roles
{
public const string Administrator = "Administrator";
public const string OtherSampleRole = "OtherSampleRole";
}

Here’s the WebForm version:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class AllowAttribute : Attribute
{
public AllowAttribute(params string[] allowedRoles)
{
//if (authorized)
//return

throw new AccessDeniedException();
}
}

This one is used like this:

    [Allow(Roles.Administrator, Roles.OtherSampleRole)]
public class SamplePage : System.Web.UI.Page
{
/*...*/
}

The WebForm version is based on page instead of by action like on the MVC sample. Pretty simple stuff…hope this helps.

Also, you'll need to add the 401 code to the custom errors section and redirect to an access denied page.

Thanks for reading!

Shout it

kick it on DotNetKicks.com

Monday, February 28, 2011

A Broken Window Post




I apologize for anyone reading this in a reader, but I couldn’t not post in the month of February. I don’t want this month to be my broken window that causes me to stop blogging.

I’m of the mindset that if I don’t blog at least once a month, I won’t continue to blog. So this is a post reminding you to not keep a broken window broken. Do something to fix it :)

kick it on DotNetKicks.com

Sunday, January 02, 2011

Allowing HTML with iFrames and jQuery




So I’ve had a problem of displaying other people’s HTML on my page and their invalid HTML messing up my page’s formatting. So, I found a solution after digging through the Outlook Web Application (OWA) HTML to see how they handle the issue. I do it a little differently, but the idea is the same.

Basically, you have a blank page in an iFrame and you insert the encoded HTML into that blank page. Here’s how I do it:

Setup a blank.htm like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
html xmlns="http://www.w3.org/1999/xhtml" >
<
head>
<
title></title>
</
head>
<
body>
<
div id="htmlcontent"></div>
</
body>
</
html>

Okay, so now on the page you need to display the HTML, you add this:

<iframe id="htmlcontent" frameborder="0" src="/blank.htm" width="600" height="400" style="background: #fff; margin: 0; padding: 0; border: 0">
<
p>Your browser does not support iframes.</p>
</
iframe>

Now all we need to do is setup the jQuery like this:

<script language="javascript" type="text/javascript">
function showHtml(id) {
$(
"#htmlcontent").contents().find("#htmlcontent").html($('#' + id).text());
}
</
script>

Now to call the jQuery:

<a href="#" onclick="showHtml('myEncodedHtmlDiv');">Sample Link</a>
<
div id="myEncodedHtmlDiv" style="display: none">&lt;p&gt;&lt;strong&gt;Greetings from the Encoded Sample!&lt;/strong&gt;</div>

With ASP.NET, you can do Server.HTMLEncode(htmlToEncode) to encode whatever string you want. The jQuery automatically decodes it when you call the .text() inside the .html() like I did above.

If you want the HTML to show up in a modal, all you need to add is this:

<div id="htmlmsg" style="display: none" class="modal">
<
iframe id="htmlcontent" frameborder="0" src="/blank.htm" width="600" height="400" style="background: #fff; margin: 0; padding: 0; border: 0">
<
p>Your browser does not support iframes.</p>
</
iframe>
</
div>
<
div id="overlay" style="display: none"></div>

Here’s the CSS to tag along:

#overlay {position: absolute;
left: 0px;
top: 0px;
width:100%;
height:100%;
text-align:center;
z-index: 1000;
background: #eeeeee 50% 50% repeat; opacity: .80;filter:Alpha(Opacity=80);
}

.modal { z-index: 10000;
position: absolute;
top: 100px;
margin: 0 auto;
background: #fff;
border:1px solid #ccc;
padding:10px;
text-align:center
}

Now you’re done. Please comment if you have any questions. Thanks for reading!


Shout it

kick it on DotNetKicks.com

Tuesday, December 07, 2010

WebFormContrib – Sample Part 3




This sample on the WebFormContrib mini-framework is on how to do a form post. If you’d like a particular sample on how to do something or if I’m missing something, please leave a comment.

Here’s how…

  1. Create a New Web Site of Use an Existing
  2. Download and reference the WebFormContrib.DLL
  3. Delete the CodeFile=”Default.aspx.cs” Inherits=”_Default” in the <%@ Page area
  4. Delete the actual Default.aspx.cs file attached to the Default.aspx page
  5. Create a new Class in the App_Code folder ( I’m calling mine DefaultPage )
  6. Inherit the DefaultPage from BasePage<SampleEmployeeView>
  7. Create a new Class file called SampleEmployeeView and make it look like this:
public class SampleEmployeeView
{
[
Required("Id is Required.")]
public int Id { get; set; }
[
Required("First Name is Required.")]
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }

//Could use AutoMapper
public static SampleEmployeeView MapEmployeeToView(Employee employee)
{
var view = new SampleEmployeeView();
view.FirstName = employee.Name.FirstName;
view.LastName = employee.Name.LastName;
view.EmailAddress = employee.EmailAddress;
view.Id = employee.Id;
return view;
}

//Could use AutoMapper
public Employee MapToEmployee()
{
var emp = new Employee();
emp.Name.FirstName = FirstName;
emp.Name.LastName = LastName;
emp.EmailAddress = EmailAddress;
emp.Id = Id;
return emp;
}
}

Employee Class & Person Class look like this:

public class Employee
{
public Employee()
{
Name =
new PersonName();
}
public int Id { get; set; }
public PersonName Name { get; set; }
public string EmailAddress { get; set; }
}

public class PersonName
{
public PersonName(){}
public PersonName(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
}

  1. In the DefaultPage Class create in Step 6, add the following code:

public class DefaultPage : BasePage<SampleEmployeeView>
{
private IRepository rep;
protected void Page_Load(object sender, EventArgs e)
{
rep =
DI.CreateSampleRepository();
if(Page.IsPostBack)
return;

getEmployee();
}

private void getEmployee()
{
//Pass in ID here to load employee into view.
ViewModel = SampleEmployeeView.MapEmployeeToView(rep.GetEmployeeBy(ViewModel.Id));
}

protected void SaveEmployee(object sender, EventArgs e)
{
if (!ModelIsValid(ViewModel))
return;

rep.Save(ViewModel.MapToEmployee());
C<
HtmlGenericControl>("successmsg").Visible = true;
}
}

Notice the ModelIsValid(ViewModel), which checks the validators set on the ViewModel. I considered using Castle Validators, but I preferred to not have any 3rd party references. I sometimes get annoyed when an open-source project has a lot of dependencies on other projects. Anyhow…


  1. Now we need to setup a dummy repository and service locator like this:

public class DI
{
public static IRepository CreateSampleRepository()
{
return new SampleRepository();
}
}

public class SampleRepository : IRepository
{
public Employee GetEmployeeBy(int employeeId)
{
//Get Employee from DB here.
return new Employee {EmailAddress = "test@test.com", Id = 123, Name = new PersonName("John", "Doe")};
}

public void Save(Employee employee)
{
//Save Employee here.
}
}

public interface IRepository
{
Employee GetEmployeeBy(int employeeId);
void Save(Employee employee);
}

  1. And finally the HTML portion of the site…the “cool” part:

<%@ Page Language="C#" AutoEventWireup="true"  Inherits="DefaultPage" %>
<%
@ Import Namespace="WebFormContrib.Helpers" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<
html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
<
title></title>
</
head>
<
body>
<
form id="form1" runat="server">
<
div>
<
div id="successmsg" runat="server" enableviewstate="false" visible="false">Saved Successfully.</div>
<%=ErrorMessages.ToList("Important Message") %>
<p><%=Html<TextBox>(f=>f.FirstName).Label("First Name:<br/>") %></p>
<
p><%=Html<TextBox>(f=>f.LastName).Label("Last Name:<br/>") %></p>
<
p><%=Html<TextBox>(f=>f.EmailAddress).Label("Email Address:<br/>") %></p>
<
p><%=Html<HiddenField>(f=>f.Id) %></p>
<
p><asp:Button ID="bSave" runat="server" Text="Save" OnClick="SaveEmployee" /></p>
</
div>
</
form>
</
body>
</
html>

Finished view should look like this:

image

Download the sample project here.

Please comment if you have any questions or suggestions. Thanks for reading!

Shout it

kick it on DotNetKicks.com

Saturday, December 04, 2010

WebFormContrib – Sample Part 2




This sample on the WebFormContrib mini-framework is a mixture of a form post and viewing an item. If you’d like a particular sample on how to do something or if I’m missing something, please leave a comment.

Down to the code…

  1. Create a New Web Site of Use an Existing
  2. Download and reference the WebFormContrib.DLL
  3. Delete the CodeFile=”Default.aspx.cs” Inherits=”_Default” in the <%@ Page area
  4. Delete the actual Default.aspx.cs file attached to the Default.aspx page
  5. Create a new Class in the App_Code folder ( I’m calling mine DefaultPage )
  6. Inherit the DefaultPage from BasePage<SampleDataView>
  7. Create a new Class file called SampleDataView and make it look like this:
public class SampleDataView
{
public SampleDataView()
{
Employees =
new List<Employee>();
SelectedEmployee =
new Employee();
}
public IList<Employee> Employees { get; set; }
public Employee SelectedEmployee { get; set; }
public string SelectedEmployeeEmailAddress { get; set; }
}

My Employee class looks like this:

public class Employee
{
public Employee(){}
public Employee(string firstName, string lastName, string email)
{
FirstName = firstName;
LastName = lastName;
Email = email;
}

public string DisplayName {get { return FirstName + " " + LastName;}}
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

  1. In the DefaultPage Class create in Step 6, add the following code:

public class DefaultPage : BasePage<SampleDataView>
{
private IRepository rep;
protected void Page_Load(object sender, EventArgs e)
{
rep =
DI.CreateSampleRepository();
initializePage();
}

private void initializePage()
{
ViewModel.Employees = rep.GetAllEmployeesResult;
}

protected void getEmployee(object sender, EventArgs e)
{
ViewModel.SelectedEmployee = rep.GetEmployeeBy(ViewModel.SelectedEmployeeEmailAddress);
}
}
  1. Create the IRepository Interface and a new DI Class that look like these:
public interface IRepository
{
IList<Employee> GetAllEmployeesResult { get; }
Employee GetEmployeeBy(string emailAddress);
}
public class DI
{
public static IRepository CreateSampleRepository()
{
return new SampleRepository();
}
}
  1. Let’s implement the IRepository real quick with a Class called SampleRepository. Looks like this:
public class SampleRepository : IRepository
{
public IList<Employee> GetAllEmployeesResult
{
get
{
var list = new List<Employee>();
list.Add(
new Employee("John", "Smith", "john@test.com"));
list.Add(
new Employee("Cindy", "Sue", "sue@test.com"));
list.Add(
new Employee("Speed", "Racer", "speed@test.com"));
list.Add(
new Employee("Joan", "Arc", "joan@test.com"));
return list;
}
}
public Employee GetEmployeeBy(string emailAddress)
{
return GetAllEmployeesResult.SingleOrDefault(x => x.Email == emailAddress);
}
}
  1. Now we get to see the fun part, the HTML code :)
<%@ Page Language="C#" AutoEventWireup="true" Inherits="DefaultPage" %>
<%
@ Import Namespace="WebFormContrib.Helpers" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<
html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
<
title></title>
</
head>
<
body>
<
form id="form1" runat="server">
<
div>
<%=Html<DropDownList>(f=>f.SelectedEmployeeEmailAddress)
.Options(ViewModel.Employees, f=>f.DisplayName, f=>f.Email)
.Selected(ViewModel.SelectedEmployeeEmailAddress)
%>
<asp:Button ID="bLoadEmployee" runat="server" Text="Display Employee" OnClick="getEmployee" />

<
p>Selected Employee:<br />
Email <
strong><%=ViewModel.SelectedEmployee.DisplayName %></strong> at <%=ViewModel.SelectedEmployee.Email %></p>
</
div>
</
form>
</
body>
</
html>

You will notice the new DropDownList with Options and Selected extension methods. The Options extension has 2 other overloads that accepts the IEnumerable<string> or IEnumerable<ListItem> so you don’t have to specify the datafield and valuefield. The Selected extension gets the value of what needs to be selected after the postback or during an initial load.

When you run the app, you should see this:

image

After clicking Display Employee:

image

Download the sample project here.

Please comment if you have any questions or suggestions. Thanks for reading!


Shout it

kick it on DotNetKicks.com

Thursday, December 02, 2010

WebFormContrib – Sample Part 1




After using the WebFormContrib mini-framework the past couple weeks, I’ve grown to really like it. I thought I’d share some of the ways I’m using it in hopes that you might benefit from it too.

This first sample is on how to show data on a page and not have to worry about any of the form elements. We will also not use any asp.net controls like gridviews, literals, or labels. So, here we go using Visual Studio 2008…

  1. Create a New Web Site or Use an Existing
  2. Download and reference the WebFormContrib DLL
  3. Delete the CodeFile="Default.aspx.cs" Inherits="_Default" in the <%@ Page area
  4. Delete the actual ….aspx.cs
  5. Create a new Class file in the App_Code folder ( I called mine DefaultPage)
  6. Inherit the DefaultPage from BasePage<SampleDataView>
  7. Create a new Class file called SampleDataView and make it look like this:
public class SampleDataView
{
public SampleDataView()
{
Employees =
new List<Employee>();
}
public string DepartmentName { get; set; }
public IList<Employee> Employees { get; set; }
public int TotalEmployees { get { return Employees.Count; } }
}

The above class is just made up of some practical things that your view might contain. My Employee class just looks like this:

public class Employee
{
public Employee(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}

public string FirstName { get; set; }
public string LastName { get; set; }
}

  1. Back in the DefaultPage Class that we created in Step 6, add the following code:

public class DefaultPage : BasePage<SampleDataView>
{
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
return;

initializePage();
}

private void initializePage()
{
//this is where you'd call your repository and possibly automapper to map from your domain model to your view model
ViewModel.DepartmentName = "Sample Department";
ViewModel.Employees.Add(
new Employee("John", "Smith"));
ViewModel.Employees.Add(
new Employee("Cindy", "Sue"));
ViewModel.Employees.Add(
new Employee("Speed", "Racer"));
ViewModel.Employees.Add(
new Employee("Joan", "Arc"));
}
}

  1. Now we can setup our view in the Default.aspx page like this:

<%@ Page Language="C#" AutoEventWireup="true" Inherits="DefaultPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<
html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
<
title>WebFormContrib Sample Part 1</title>
</
head>
<
body>
<
form id="form1" runat="server">
<h3><%=ViewModel.DepartmentName %></h3>
<
p>Total Employees: <%=ViewModel.TotalEmployees %></p>
<
ul>
<% foreach (var employee in ViewModel.Employees) {%>
<li><%=employee.FirstName %> <%=employee.LastName %></li>
<% }%>
</ul>
</form>
</
body>
</
html>

As you can see, it looks pretty much exactly like MVC and it allows you to keep complete control of your HTML. When you run your app, you should see this:

image

Download the sample project here.

Please comment if you have any questions or suggestions. Thanks for reading!


Shout it

kick it on DotNetKicks.com

Related Posts Plugin for WordPress, Blogger...