3/20/11

View Product - Online Catalog Example using ASP.NET MVC 3

View Product URL: http://mvc.expressionsoftware.com/products/1000

Route
routes.MapRoute("view product",
                "products/{id}",
                new { controller = "Product",
                      action = "ViewProduct" });

Controller: \controllers\productController.cs
[HttpGet]
public ActionResult ViewProduct(int id)
{
    var product = Cache.GetProduct(id);
    return View(product);
}

Product Model Class & Object
namespace ExpressionSoftware.Model
{
   public class Product
   {
     public int Id { get; set; }
     public string Name { get; set; }
     public string Description { get; set; }

     public decimal Price { get; set; }
     public string Status { get; set; }
     public bool InStock { get; set; }
     public int StockCount { get; set; }

     public Dictionary<string, string> Metadata { get; set; }
   }
}

new Product() {
                Id = 1000,
                Name = "Foo",
                Description = "Some Foo...",
  
                Price=999.99m,
                Status = "In Stock",
                InStock = true,
                StockCount = 10,
  
                Metadata = new Dictionary<string, string>()
                {
                  { "Color", "Blue"},
                  { "Size", "30 x 16"},
                  { "Manufacturer", "Foo Makers Inc, USA"},
                }

              },

View: \views\product\viewProduct.cshtml
@model ExpressionSoftware.Model.Product
@{Layout = null;}

<!doctype html>
<html>
<head>
  <title>@Model.Name - Products</title>
  <link href="../../ux/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
  <h1>@Model.Name</h1>
  Id: @Model.Id<br />
  Description: @Model.Description<br /><br />

  Status: @{  //************************************
              if (@Model.InStock) {
                <span class="instock">@Model.Status</span><br />
                @:Count Available: @Model.StockCount
              }
              else {
                @Model.Status
              }
          }<br />

   Price: $@Model.Price<br /><br />
   
   @{  //************************************
       //metadata
       if (Model.Metadata != null) {
         foreach (var kvp in Model.Metadata) {
           @string.Format("{0}: {1}", kvp.Key, kvp.Value);<br />
         }
       }
   }<br />

   @{  //************************************
       <!-- wip - add to cart form / post action -->
       if (@Model.InStock) {
         <input type="submit" value="Add to Cart" />
       }
   }
</body>
</html>

Output HTML
<!doctype html>
<html>
<head>
  <title>Foo - Products</title>
  <link href="../../ux/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
  <h1>Foo</h1>
  
  Id: 1000<br />
  Description: Some Foo...<br /><br />

  Status: <span class="instock">In Stock</span><br />
  Count Available: 10<br />
  Price: $999.99<br /><br />

  Color: Blue<br />
  Size: 30 x 16<br />
  Manufacturer: Foo Makers Inc, USA<br /><br />
  
  <!-- wip - add to cart form / post action -->
  <input type="submit" value="Add to Cart" />
</body>
</html>



3/2/11

Integrating reCAPTCHA with ASP.NET MVC 3

Example using reCAPTCHA in an email-contact page.

www.google.com/recaptcha
code.google.com/apis/recaptcha
www.google.com/recaptcha/api/verify


RecaptchaController Class



\controllers\recaptcha\recaptchaController.cs
using System.Web.Mvc;

namespace ExpressionSoftware.Controllers
{
    public class RecaptchaController : Controller
    {
        //********************************************************
        // PRIVATE DATA - DO NOT HARDCODE
        
           const string RECAPTCHA_PRIVATE_KEY = "----------";
           const string EMAIL_ADDRESS = "john@email.com";
        
        //********************************************************

        const string RECAPTCHA_VERIFY_URL = "http://www.google.com/recaptcha/api/verify";
        
        [AcceptVerbs(HttpVerbs.Get)]
        public ViewResult Default()
        {
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public string Default(FormCollection formValues)
        {
            string result = "fail";
            
            //do not submit recaptcha if form vars are null/empty
            if (!(string.IsNullOrEmpty(formValues["recaptcha_challenge_field"]) ||
                  string.IsNullOrEmpty(formValues["recaptcha_response_field"])))
            {
                //alt - validate using web service
                var recaptcha = new ExpressionSoftware.Recaptcha() { PrivateKey = RECAPTCHA_PRIVATE_KEY,
                                                                     VerifyUrl = RECAPTCHA_VERIFY_URL };

                if (recaptcha.Validate(Request.UserHostAddress, formValues["recaptcha_challenge_field"], 
                                                                formValues["recaptcha_response_field"]))
                {
                    result = EMAIL_ADDRESS;  //captcha test passed, show email address
                }
            }
            return result;
        }
    }
}

\views\recaptcha\default.cshtml
<h2>reCAPTCHA Demo for ASP.NET MVC 3</h2>

@using (Html.BeginForm()) {
<input id="b1" type="button" value="Show CAPTCHA" />
<a id="email" />
<div id="captchaDiv"></div>
<input id="submit" type="submit" value="Submit" style="display:none;"/>
<label id="error" style="display:none;">Invalid input, please try again.</label>    
}

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js" type="text/javascript"></script>
<script src="//www.google.com/recaptcha/api/js/recaptcha_ajax.js" type="text/javascript"></script>
<script src="/js/recaptcha.js" type="text/javascript"></script>

\js\recaptcha.js
$(document).ready(function() {
  $("form").submit(
    function(event) {
      event.preventDefault();
      submit(this, updateUI, "html");
    });
  $("#b1").click(showCaptcha);
});

function submit(form, callback, format) {
  $.ajax({url: form.action,
          type: form.method,
          dataType: format,
          data: $(form).serialize(),
          success: callback
         });
}

function updateUI(result) {
  result = $.trim(result);
  
  if (result == "fail") {
    $("#error").show();
    Recaptcha.reload();
    Recaptcha.focus_response_field();
  }
  else {  //success
    $("#email").text(result);
    $("#email")[0].href = "mailto:"+result;
    $("#captchaDiv").hide();
    $("#submit").hide();
    $("#error").hide();
  }
}

function showCaptcha() {
  Recaptcha.create("6LdXGMISAAAAAKbqYwaabU7h1qjwGYEXoEelZjWV",  //api public key
                   "captchaDiv",
                   {
                     theme: "clean",
                     callback: Recaptcha.focus_response_field
                   }
                  );
  $("#b1").hide();
  $("#submit").show();
  return false;
}


Recaptcha Class / Web Service



recaptcha.cs
using System.IO;
using System.Net;
using System.Text;

namespace ExpressionSoftware
{
    public class Recaptcha
    {
        public string VerifyUrl { get; set; }
        public string PrivateKey { get; set; }

        public bool Validate(string remoteIP, string captchaChallenge, string captchaResponse)
        {
            bool result = false;
            string response = GetWebResponse(remoteIP, captchaChallenge, captchaResponse);
            result = response.ToLower().StartsWith("true");  //api response line 1 value: true or false
            return result;
        }

        string GetWebResponse(string remoteIP, string captchaChallenge, string captchaResponse)
        {
            string result = null;

            //convert params to byte array
            var parameters = string.Format("privatekey={0}&remoteip={1}&challenge={2}&response={3}",
                                           PrivateKey, remoteIP, captchaChallenge, captchaResponse);
            byte[] paramData = Encoding.UTF8.GetBytes(parameters);

            var request = (HttpWebRequest)WebRequest.Create(VerifyUrl);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = paramData.Length;
            request.ServicePoint.Expect100Continue = false;
            
            //write param data to request stream
            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(paramData, 0, paramData.Length);
                requestStream.Close();
            }

            using (WebResponse response = (HttpWebResponse)request.GetResponse())
            {
                using (Stream stream = response.GetResponseStream())
                {
                    using (StreamReader responseReader = new StreamReader(stream))
                    {
                        result = responseReader.ReadToEnd();
                        responseReader.Close();
                    }
                    stream.Close();
                }
                response.Close();
            }
            return result;
        }
    }
}