Skip to content

Welcome

Welcome to my blog about the software tools / techniques I have used.

The first posts, were originally hosted in a variety of places,  &  I thought it would be nice to bring them all together.   Its mainly a journal of  some of the things I have worked on, that might be useful to me in the future.  If it helps anyone else, then great.

I have been developing Web Applications with Domino / Lotus Notes since the 90s, mainly in areas where workflow & security are important. Before that I worked on financial systems with Foxpro, Oracle & PL/1.

In parallel with Domino, recently I have used Java , PHP, C# .NET, Sharepoint, JQuery , HTML5 and a bit of  Ruby On Rails.

Security is a bit of a hobby horse of mine – so its bound to crop up once or twice.  If you’ve found this site, please do check out OWASP  The Open Web Application Security Project – it has some great FREE stuff that helps build more secure applications.

Richard in Warwick.

NUnit validation of a web service at “http://localhost:1234/api/values”;

NUnit validation of a web service at “http://localhost:1234/api/values”;

UnitTest.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MVCWebApi.Controllers;
using NUnit.Framework;
using System.Web.Http;
using System.Net.Http;
using MVCWebApi.Models;
using System.Configuration;
using System.Net;
using System.Net.Http.Headers;
using Newtonsoft.Json;
namespace MVCWebApi.Controllers.Tests
{
[TestFixture()]
public class UnitTest1
{

private string UrlBase = “http://localhost:49493/”;
private string servicePath = “api/values”;
private HttpClient client;
private HttpResponseMessage response;
private string jsonData;
private List<Person> list;

[SetUp]
public async void SetUP()
{

client = new HttpClient();
client.BaseAddress = new Uri(UrlBase);

// get service header data into a queryable form

response = client.GetAsync(servicePath).Result;
// assuming service works load json into a string
jsonData = client.GetStringAsync(servicePath).Result;

// Parse json into a custom c# class – in this case, Person
list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Person>>(jsonData);
}
// Test for OK status code

[Test]
public void GetResponseIsSuccess()
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
// Test for returned data is JSON

[Test]
public void GetResponseIsJson()
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));

Assert.AreEqual(“application/json”, response.Content.Headers.ContentType.MediaType);
}

// Test for authentication

[Test]
public void GetAuthenticationStatus()
{
Assert.AreNotEqual(HttpStatusCode.Unauthorized, response.StatusCode);

}
// Test parsed ( people) object contains data from the json

[Test]
public void jsonIsvalid()
{
Assert.GreaterOrEqual(list.Count, 0);

}

// Test parsed ( people) object contains a value for specific name

[Test]
public void jsonIsvalid2()
{
bool found = false;
foreach (Person people in list)
{
if (people.Name == “sankar parida”)
{ found = true; }
}

Assert.IsTrue(found);
}

// Test parsed ( people) object contains another specific name

[Test]
public void jsonIsvalid3()
{
bool found = false;
foreach (Person people in list)
{
if (people.Address == “cuttack”)
{ found = true; }
}

Assert.IsTrue(found);
}
}
}

Where MVCWebApi looks like

API / ValuesController

using MVCWebApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace MVCWebApi.Controllers
{
public class ValuesController : ApiController
{
PersonEntities db = new PersonEntities();
// GET api/values
public IEnumerable<Person> Get()
{
return db.Persons.ToList();
//return new string[] { “value1″, “value2″ };
}
// GET api/values/5
public Person Get(int id)
{
return db.Persons.Find(id);
//return “value”;
}
// POST api/values
public void Post(List<string> val)//(Person obj )
{
try
{
Person obj = new Person();
obj.Name = val[0];
obj.Address = val[1];
obj.DOB = Convert.ToDateTime(val[2]);
db.Persons.Add(obj);
db.SaveChanges();
}
catch (Exception) { }
}
// PUT api/values/5
public void Put(int id, Person obj)//(int id, [FromBody]string value)
{
try
{
db.Entry(obj).State = System.Data.EntityState.Modified;
db.SaveChanges();
}
catch (Exception) { }
}
//This method for update through Json
public void Put(List<string> val)
{
try
{
int id = Convert.ToInt32(val[3]);
Person obj = db.Persons.Find(id);
obj.Name = val[0];
obj.Address = val[1];
obj.DOB = Convert.ToDateTime(val[2]);
db.Persons.Add(obj);
db.Entry(obj).State = System.Data.EntityState.Modified;
db.SaveChanges();
}
catch (Exception) { }
}
// DELETE api/values/5
public void Delete(int id)
{
Person obj = db.Persons.Find(id);
db.Persons.Remove(obj);
db.SaveChanges();
}
}
}

Controllers / PersonController is

using MVCWebApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MVCWebApi.Controllers
{
public class PersonController : Controller
{
ValuesController db = new ValuesController();
public ActionResult Index()
{
var list = db.Get(); //Getting List of records from web API
return View(list);
}
public ActionResult Index2()
{
return View();
}
public ActionResult Details(int id)
{
Person person = db.Get(id);
return View(person);
}

public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Person obj)
{
try
{
List<string> person = new List<string>();
person.Add(obj.Name);
person.Add(obj.Address);
person.Add(obj.DOB.ToString());
db.Post(person);
return RedirectToAction(“Index”);
}
catch
{
return View();
}
}

public ActionResult Edit(int id)
{
Person person = db.Get(id);
return View(person);
}
[HttpPost]// POST: /Person/Edit/5
public ActionResult Edit(int id, Person obj)
{
try
{
db.Put(id, obj);
return RedirectToAction(“Index”);
}
catch
{
return View();
}
}

// GET: /Person/Delete/5
public ActionResult Delete(int id)
{
Person person = db.Get(id);
return View(person);
}
[HttpPost]// POST: /Person/Delete/5
public ActionResult Delete(int id, FormCollection collection)
{
try
{
db.Delete(id);
return RedirectToAction(“Index”);
}
catch
{
return View();
}
}
}
}

Person.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace MVCWebApi.Models
{
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public DateTime DOB { get; set; }
}
public class PersonEntities : DbContext
{
public DbSet<Person> Persons { get; set; }
}
}

TSQL Syntax to get useful data from Sharepoint usage logs

SELECT DocumentPath
,Replace(Replace(Reverse(LEFT(REVERSE([DocumentPath]),Charindex(‘/’,REVERSE([DocumentPath])))),’/’,”),’%20′,’ ‘) As DocName
, logtime
, REPLACE(UserLogin,’myDomain\’,”) as UserId
, Convert(date,LogTime) as DateLogged
, CONVERT(time(0),logtime) as TimeLogged
, ReferrerUrl
, SubString(DocumentPath+’/’, (CHARINDEX(‘/’, DocumentPath+’/’, 0) + 1)
, (CharIndex(‘/’, RIGHT(DocumentPath+’/’, (LEN(DocumentPath+’/’) – (CharIndex(‘/’, DocumentPath+’/’, 0)))), 0) – 1)) As TeamSite
,Replace(item,’%20′,’ ‘) as DocumentSet
FROM [SharepointDomain].[dbo].[RequestUsage]
CROSS APPLY dbo.DelimitedSplit8K(DocumentPath,’/’) split
 WHERE DocumentPath like ‘/ascs/%’
  And DocumentPath not like ‘%dll’
  And DocumentPath not like ‘%asmx’
  And DocumentPath not like ‘%_vti_bin%’
  And DocumentPath not like ‘%_layouts%’
This uses the following features to get levels out of the URL
SubString(DocumentPath+’/’, (CHARINDEX(‘/’, DocumentPath+’/’, 0) + 1)
, (CharIndex(‘/’, RIGHT(DocumentPath+’/’, (LEN(DocumentPath+’/’) – (CharIndex(‘/’, DocumentPath+’/’, 0)))), 0) – 1)) As TeamSite
Jeff Modens DelimitedSplit8k to parse out the second level of the url
Replace(Replace(Reverse(LEFT(REVERSE([DocumentPath]),Charindex(‘/’,REVERSE([DocumentPath])))),’/’,”),’%20′,’ ‘) As DocName


DROP FUNCTION dbo.DelimitedSplit8K
GO
 CREATE FUNCTION dbo.Split8K
/***************************************************************************************************
 Purpose:
 Split a given string at a given delimiter and return a list of the split elements (items).

 Returns:
 iTVF containing the following:
 ItemNumber = Element position of Item as a BIGINT (not converted to INT to eliminate a CAST)
 Item       = Element value as a VARCHAR(8000)

 CROSS APPLY Usage Example:
---------------------------------------------------------------------------------------------------
--===== Conditionally drop the test tables to make reruns easier for testing.
     -- (this is NOT a part of the solution)
     IF OBJECT_ID('tempdb..#JBMTest') IS NOT NULL 
        DROP TABLE #JBMTest
;
--===== Create and populate a test table on the fly (this is NOT a part of the solution).
 SELECT *
   INTO #JBMTest
   FROM (
         SELECT 1,'1,10,100,1000,10000,100000,1000000' UNION ALL
         SELECT 2,'2000000,200000,20000,2000,200,20,2' UNION ALL
         SELECT 3, 'This,is,a,test'                    UNION ALL
         SELECT 4, 'and so is this'                    UNION ALL
         SELECT 5, 'This, too (no pun intended)'
        ) d (SomeID,SomeValue)
;
GO
--===== Split the CSV column for the whole table using CROSS APPLY (this is the solution)
 SELECT test.SomeID, split.ItemNumber, split.Item
   FROM #JBMTest test
  CROSS APPLY
        (
         SELECT ItemNumber, Item
           FROM dbo.DelimitedSplit8k(test.SomeValue,',')
        ) split
;
---------------------------------------------------------------------------------------------------
 Notes:
 1. Optimized for VARCHAR(7999) or less.  No testing or error reporting for truncation at 7999
    characters is done.
 2. Optimized for single character delimiter.  Multi-character delimiters should be resolved
    externally from this function.
 3. Optimized for use with CROSS APPLY.
 4. Does not "trim" elements just in case leading or trailing blanks are intended.
 5. If you don't know how a Tally table can be used to replace loops, please see the following...
    http://www.sqlservercentral.com/articles/T-SQL/62867/
 6. Changing this function to use VARCHAR(MAX) will cause it to run twice as slow.  It's just the 
    nature of VARCHAR(MAX) whether it fits in-row or not.  Some recovery of speed can be realized
    by doing datatype matching for CHARINDEX which changes it's datatype for VARCHAR(MAX).
 7. Multi-machine testing for the method of using UNPIVOT instead of 10 SELECT/UNION ALLs shows
    that the UNPIVOT method is quite machine dependent and can slow things down quite a bit.
 8. Performance testing shows using "TOP" for the limiting criteria of "N" is actually 
    slower and slightly more CPU intensive than the traditional WHERE N < LEN(@pString) + 2. 
 9. Performance testing shows using ORDER BY (SELECT x) where "x" is anything is actually
    slower and slightly more CPU intensive than the traditional ORDER BY (SELECT N).
***************************************************************************************************/
--===== Define I/O parameters
        (
        @pString    VARCHAR(7999),
        @pDelimiter CHAR(1)
        )
RETURNS TABLE
   WITH SCHEMABINDING
AS
RETURN
--===== "Inline" CTE Driven "Tally Table” produces values up to
     -- 10,000... enough to cover VARCHAR(8000)
WITH
      E1(N) AS ( --=== Create Ten 1's
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 UNION ALL
                 SELECT 1 UNION ALL SELECT 1 --10
               ),
      E2(N) AS (SELECT 1 FROM E1 a, E1 b),   --100
      E4(N) AS (SELECT 1 FROM E2 a, E2 b),   --10,000
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT N)) FROM E4)  
--===== Do the split
 SELECT ROW_NUMBER() OVER (ORDER BY N) AS ItemNumber,
        SUBSTRING(@pString, N, CHARINDEX(@pDelimiter, @pString + @pDelimiter, N) - N) AS Item
   FROM cteTally
  WHERE N <= DATALENGTH(@pString)+1 --DATATLENGTH allows for trailing space delimiters
    AND SUBSTRING(@pDelimiter + @pString, N, 1) = @pDelimiter
;
GO

C# function for file upload to convert HttpPostedFileBase to byte array.

The commented code is here for comparison.   This had the drawback that it generated binary nulls after the end of file marker.  Some PDF files were corrupted by that code.

private byte[] readFileContents(HttpPostedFileBase file)
{
Stream fileStream = file.InputStream;
var mStreamer = new MemoryStream();
mStreamer.SetLength(fileStream.Length);
fileStream.Read(mStreamer.GetBuffer(), 0, (int)fileStream.Length);
mStreamer.Seek(0, SeekOrigin.Begin);
byte[] fileBytes = mStreamer.GetBuffer();

//////using (MemoryStream ms = new MemoryStream())
//////{
////// file.InputStream.CopyTo(ms);
////// fileBytes = ms.GetBuffer();
//////}

return fileBytes;
}

 

Typical use may be within MVC …..   EG

[HttpPost]
public ActionResult Create(myMetaDataClass collection, HttpPostedFileBase uploadfile)
{

// Other code

byte[] fileContents = null;
fileContents = readFileContents(uploadfile);

///other code to put the filecontents into form that can be posted to a web service defined by serviceurl

StringBuilder stringBuilder = new StringBuilder();

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceurl);

StringBuilder stringBuilder = new StringBuilder();
// code to parse out myMetaDataClass collection into parameters for webservice

stringBuilder.Append(postParameterKeys.ElementAt(1) + “=” +
HttpUtility.UrlEncode(Convert.ToBase64String(fileContents)) + “&”);

//More string builder code
//

byte[] postData = Encoding.UTF8.GetBytes(stringBuilder.ToString());

request.ContentLength = postData.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(postData, 0, postData.Length);
}

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
//etc…..

Dynamic JQGrid definition with Razor… & time sensitive toastr..

Build JavaScript Functions to format a url based on that row : This one has a bootstrap button in it, for a “Delete” function

 function fmatDelLnk(cellvalue, options, rowObject) {

var file_name = rowObject[6].toString();

var catref = rowObject[7].toString();

var ServiceURL = $(‘#ServiceURL’).val();

var link=”/Document/Del?identifier=” + $_GET["identifier"] + “&cat=” + catref + “&empid=” + $_GET["empid"] + “&filename=” +  file_name ;

var url = “<a href='” + link + “‘ class=’btn btn-mini ‘ style=’color:white;font-weight:bold’>Delete</a>”;

return url

}

( The inline css is to fix a conflict between bootstrap & other css for hrefs on the page)

//Similar function but with text as a link.  The blank on the end of label is to make the entire cell clickable

   function fmatDLnk(cellvalue, options, rowObject) {

var  file_name  = rowObject[6].toString();

var label = rowObject[1].toString()+”                                  “;

var catref = rowObject[7].toString();

var WebServiceURL = $(‘#WebServiceURL’).val();

var urlLink = “<a href=/Document/Launch?identifier=” + $_GET["identifier"] + “&cat=” + catref + “&empid=” + $_GET["empid"] + “&filename=” +  file_name  + “>” + label+”</a>”;

return urlLink

}

//Similar function but for use in another column. Its label for the href would be different

function fmatELnk(cellvalue, options, rowObject) {

etc…….

}

JQuery to run when the form opens

//Controls whether or not to display a toastr alert from an update function.  This page is launched directly & is a redirect page after updates.  #LastDbUpdate is a form field populated from a session variable indicating when an update was successful

$(document).ready(function () {

var dstr = $(‘#LastDbUpdate’).val();

// max diff is the cutoff period in milliseconds  after which we ignore the update parm 

       var maxdiff = 10000;

var updateVal = $(‘#update’).val();

var diff = maxdiff + 90;

var currTime = new Date();

var LstUpdDte = new Date();

LstUpdDte.setDate(LstUpdDte.getDate() – 1);

// #LastDbUpdatestored on server as the last datetime this user updated the database. All components are seprated by “:” 

       if (dstr != “”)

{   var d  = dstr.split(“:”);

for (var i in d )

{

d[i] = parseInt(d [i], 10);

}

LstUpdDte = new Date(d[0], d[1]-1,d[2], d[3], d[4], d[5],0);

diff = currTime.getTime() – LstUpdDte.getTime();

var d_dte = LstUpdDte.toTimeString().substr(0, 5);

// if an update happened in the last 10000 milliseconds, then display the toastr message 

 

if ((updateVal == ‘true’) && ( diff<maxdiff))

{

toastr.options = {

//                  … assorted toastr display parms

}

toastr.success(“Database updated  ” + d_dte )

}

 

// Build dynamic array for jqgrid determining whether or not to add columns, & making the content reusable between different tables ( EG in a Tabbed interface)

$(function () {

var colMdl = [];

// Add each column definition one at a time to the array, the formatters are doclinks set by the above js functions. Not all the formatters have been included above

colMdl.push({ name: ‘id’, index: ‘id’, hidden: true });

colMdl.push({ name: ‘title’, index: ‘title’, width: 330, formatter: fmatDLnk });

colMdl.push({ name: ‘effectivedate’, index: ‘effectivedate’, width: 105, formatter: fmatELnk });

colMdl.push({ name: ‘assignmentid’, index: ‘assignmentid’, hidden: true });

colMdl.push({ name: ‘createdby’, index: ‘createdby’, width: 105, formatter: fmatCbyLink });

colMdl.push({ name: ‘createddate’, index: ‘createddate’, width: 105, formatter: fmatCDteLnk });

colMdl.push({ name: ‘linkfilename’, index: ‘linkfilename’, hidden: true });

colMdl.push({ name: ‘categoryreferencenumber’, index: ‘categoryreferencenumber’, hidden: true });

 

//Razor if test to determine whether or not add the “Delete” Button as a cell in the row 

       @if (User.IsInRole(“myCustomRole”)) {

<text>

colMdl.push({ name: ‘Delete’, width: 150, formatter: fmatDelLnk });

</text>

}

var colHdr = ['Id', 'Document Title', 'Effective Date', '', 'Created By', 'Created Date', 'Link Filename', 'Category Reference'];

//Razor if test to determine whether or not add the “header” column for a delete button

@if (User.IsInRole(“myCustomRole”)) {

<text>

colHdr.push(‘Actions’);

</text>

}

//Sample table to position code on page  

 

jQuery(“#cat1″).jqGrid({

url: ‘/DocsJSON/read?ident=’+$_GET["ident"] + ‘&empid=’ + $_GET["empid"] + ‘&cat=1′,

datatype: “json”,

colNames: colHdr,

colModel: colMdl,

rowNum: 10,pager: ‘#pagerrecruitment’,

sortname: ‘effectivedate’,viewrecords: true,

sortorder: “desc”,height: “350px”,border: “none”

});

jQuery(“#cat1″).jqGrid(‘navGrid’, ‘#pagerrecruitment’, { edit: false, add: false, del: false, search: false, refresh: false });

 

jQuery(“#cat2″).jqGrid({

url: ‘/DocsJSON/read?ident=’+$_GET["ident"] + ‘&empid=’ + $_GET["empid"] + ‘&cat=2′,

datatype: “json”,

colNames: colHdr,

colModel: colMdl,

rowNum: 10,pager: ‘#pagerclearances’,

sortname: ‘effectivedate’, viewrecords: true,

sortorder: “desc”,height: “350px”, border: “none”

});

jQuery(“#cat2″).jqGrid(‘navGrid’, ‘#pagerclearances’, { edit: false, add: false, del: false, search: false, refresh: false });

 

etc…

Jquery, twitter, bootstrap & MVC form layout

Bootstrap is framework of css classes that simplify web form design. These are some of the conventions I found useful & how I got round the gotchas…
Required js libraries: 

<script src=”@Url.Content(“~/Scripts/jquery-1.5.1.min.js”)” type=”text/javascript”></script>
<script src=”@Url.Content(“~/Scripts/jquery.validate.js”)” type=”text/javascript”></script>
<script src=”@Url.Content(“~/Scripts/jquery.validate.unobtrusive.js”)” type=”text/javascript”></script>
<script src=”@Url.Content(“~/Scripts/modernizr-1.7.min.js”)” type=”text/javascript”></script>
<link rel=”stylesheet” href=”http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css”&gt;
<script src=”../../Scripts/bootstrap.file-input.js” type=”text/javascript”></script>
<script src=”../../Scripts/modernizr-2.5.3.js” type=”text/javascript”></script>

& associated css

Textfields

<div>
       <label>
           @Html.LabelFor(model => model.sourceURL)</label>
       <div>
           : @Html.TextBoxFor(model => model.sourceURL, new { @class = “form-control”,placeholder =”First field name” })
           @Html.ValidationMessageFor(model => model.sourceURL)
       </div>
   </div>
Built using .net razor, relying on the MVC model for validation, labeling etc,this makes it easier to cascade a description or validation through the application. .
The fieldlabel sits in a class “3” wide The field sits in a class 8 wide.     ( There is a sidebar to of width 1 to make up the 12 units bootstrapper is based on. The formcontrol class, left aligns the field. ‘placeholder’ places text in the field until it is clicked on ( Not IE 8 or )
Integer fields
       <div>
           : @Html.TextBoxFor(model => model.anInteger, new { @class = “text-right”, type=”number”,placeholder =”0″})
           @Html.ValidationMessageFor(model => model.anInteger)
       </div>
also set in col-xs-8 class @class = “text-right”, aligns the field to the right to display like a number . type=”number” places a spinner

Date fields

The HTML or razor code is set up like text .  ( even though the model is defined as a datetime) A dynamic calendar picker is created with jqueryui:
<script>
$(function () {
//Bootstrap can interfere with this, but noConflict()clears this
$.noConflict();
// When a field( eg #fromDate) is clicked in, show calendar
// When a value is picked, set a limit on a related date         
$(“#fromDate”).datepicker({dateFormat: “dd/mm/yy”,
onClose: function (sel_Dte)
{     $(“#toDate”).datepicker(“option”, “minDate”, sel_Dte);     }
});
       
$(“#toDate”).datepicker({dateFormat: “dd/mm/yy”,
onClose: function (sel_Dte)
{     $(“#fromDate”).datepicker(“option”, “maxDate”, sel_Dte);     }
     });
   });</script>

File picker

By default File pickers display differently in each browser.  This is a pain.  This website suggested hiding the file picker, & then showing a button to invoke the hidden filepickers click event & then showing its results in a field.    There were a few cross browser issues, but these were addressed as follows :
1) Place hidden file input at end of form , with an onchange event calling a javascript function myFunction
<input type=”file” name=”file” style=”visibility: hidden” id=”pdffile” onchange=”myFunction(this,’#subfile’);” />
2) Place the visible elements in a control group . These consist of a button , whose purpose is to invoke the hidden file input’s click event, & the field “subfile” to show the results:
<div>  
       <label>
           Choose A File
       </label>
       <div>
           : <input type=”text” id=”subfile”>
           <a onclick=”$(‘#pdffile’).click();”>Browse</a>
       </div>
   </div>
3) Add the javascript for myFunction()
   function myFunction(source, target) {
\\ take in a field object & the name of a target
var x = $(source).val();
\\get the value of the field from source, convert it to an array.
\\ get out the last element
       var z = x.split(“\\”).pop();
\\ set the target value
       $(target).val(z);
   }
The sequence runs as follows:
  1. User clicks visible button .
  2. Visible button invokes pdffiles.click() event
  3. This displays a file picker, whose results are returned to ‘pdffile’
  4. pdffile’s onchange event is triggered, passing itself & the name of a target id, to the function myFunction()
  5. This gets the filename element from this input field ( it could include, a filename only , the  true path or a false path)  & updates the field accordingly
@model BootStrapApp.Models.Document
@{
   ViewBag.Title = “Create”;
   Layout = “~/Views/Shared/_Layout.cshtml”;
}
<h2>Create</h2>
<script>
   function myFunction(source, target) {
       var x = $(source).val();
       var z = x.split(“\\”).pop();
       $(target).val(z);
   }
   
   $(function () {
       $.noConflict();
       $(“#fromDate”).datepicker({
           dateFormat: “dd/mm/yy”,
           onClose: function (selDte) {
               $(“#toDate”).datepicker(“option”, “minDate”, selDte);
           }
       });
       
       $(“#toDate”).datepicker({
           dateFormat: “dd/mm/yy”,
           onClose: function (selDte) {
               $(“#fromDate”).datepicker(“option”, “maxDate”, selDte);
           }
       });
   });
</script>
<form>
<fieldset>
   <legend>Document</legend>
   <div>
       <label>
           @Html.LabelFor(model => model.sourceURL)</label>
       <div>
           : @Html.TextBoxFor(model => model.sourceURL, new { @class = “form-control”,placeholder =”First field name” })
           @Html.ValidationMessageFor(model => model.sourceURL)
       </div>
   </div>
   <div>
       <label>
           @Html.LabelFor(model => model.anInteger)</label>
       <div>
           : @Html.TextBoxFor(model => model.anInteger, new { @class = “text-right”, type=”number”,placeholder =”0″})
           @Html.ValidationMessageFor(model => model.anInteger)
       </div>
   </div>
   <div>
       <label>
           @Html.LabelFor(model => model.toDate)</label>
       <div>
           : @Html.TextBoxFor(model => model.toDate, new { @class = “form-control” })
           @Html.ValidationMessageFor(model => model.toDate)
       </div>
   </div>
   <div>
       <label>
           @Html.LabelFor(model => model.fromDate)</label>
       <div>
           : @Html.TextBoxFor(model => model.fromDate)
           @Html.ValidationMessageFor(model => model.fromDate)
       </div>
   </div>
   
   <div>
 
       <label>
           Choose A File
       </label>
       <div>
           : <input type=”text” id=”subfile”>
           <a onclick=”$(‘#pdffile’).click();”>Browse</a>
       </div>
   </div>
</fieldset>
<div>
   <label for=”inputEmail”>
       Email:</label>
   <div>
       : <input type=”email” id=”inputEmail” placeholder=”Email”>
   </div>
</div>
<div>
   <label for=”inputPassword”>
       Password:</label>
   <div>
       : <input type=”password” id=”inputPassword” placeholder=”Password”>
   </div>
</div></div>
<div>
   <label for=”confirmPassword”>
       Confirm Password:</label>
   <div>
      : <input type=”password” id=”confirmPassword” placeholder=”Confirm Password”>
   </div>
</div>
<div>
   <label for=”firstName”>
       First Name:</label>
   <div>
       : <input type=”text” id=”firstName” placeholder=”First Name”>
   </div>
</div>
<div>
   <label for=”lastName”>
       Last Name:</label>
   <div>
       : <input type=”text” id=”lastName” placeholder=”Last Name”>
   </div>
</div>
<div>
   <label for=”phoneNumber”>
       Phone:</label>
   <div>
       <input type=”tel” id=”phoneNumber” placeholder=”Phone Number”>
   </div>
</div>
<div>
   <label>
       Date of Birth:</label>
   <div>
       <select>
           <option>Date</option>
       </select>
   </div>
   <label>
   </label>
   <div>
       <select>
           <option>Month</option>
       </select>
   </div>
   <label>
   </label>
   <div>
       <select>
           <option>Year</option>
       </select>
   </div>
<div>
   <label>
       Gender:</label>
   <div>
       <label>
           <input type=”radio” name=”genderRadios” value=”male”>
           Male
       </label>
   </div>
   <div>
       <label>
           <input type=”radio” name=”genderRadios” value=”female”>
           Female
       </label>
   </div>
</div>
<div>
   <div>
       <label>
           <input type=”checkbox” value=”news”>
           Send me latest news and updates.
       </label>
   </div>
</div>
<div>
   <div>
       <label>
           <input type=”checkbox” value=”agree”>
           I agree to the <a href=”#”>Terms and Conditions</a>.
       </label>
   </div>
</div>
<br>
<div>
   <div>
       <input type=”submit” value=”Submit”>
       <input type=”reset” value=”Reset”>
   </div>
</div>
     <input type=”file” name=”file” style=”visibility: hidden” id=”pdffile” onchange=”myFunction(this,’#subfile’);” />
</form>

C# MVC reports / navigation screen populated from webconfig with JQuery calendar validation & radio button.

Set the RepNams & urls as values in Web.Config. Use tilda ~ to separate the values.  Its a nice generic separator, because it is not commonly used in English words & phrases.

<appSettings>

<add key=”RepNams” value=”Rep1~Rep2~Rep3~Rep4″ />

<add key=”RepLnk” value=”http://www.google.co.uk~http://WWW.BBC.co.UK~http://www.netvibes.com~http://www.icloud.com&#8221; />

<add key=”RepNamsR” value=”Records up for disposal~Employee records opened~Employee records moved~Employee records deleted” />

<add key=”RepLnkR” value=”http://www.LindaScannell.com~http://WWW.BBC.co.UK~http://www.netvibes.com~http://WWW.BBC.co.UK&#8221; />

<add key=”RepActions” value=”All~Create~Read~Update~Delete” />

</appSettings>

Build a simple Model, to help pass data from the query string to the View, & to allow for easier expansion of validation:

public class Rep

{

[DisplayName("User ID")]

public string UserId { get; set; }

[DisplayName("Employee Id")]

public string EmployeeId { get; set; }

[DataType(DataType.Date)]

[DisplayName("Date from ")]

public DateTime FromDate { get; set; }

[DataType(DataType.Date)]

[DisplayName("Date until")]

public DateTime ToDate { get; set; }

[DisplayName("Actions to Rep on")]

public string[] RepActions { get; set; }

}

Build a controller, with an index capable of taking input parameters

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Net;

using System.Configuration;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity;

using Microsoft.Practices.EnterpriseLibrary.Security;

using Microsoft.Practices.Unity;

using myMVC_app.Common;

using myMVC_app.Models;

namespace myMVC_app.Controllers

{

[Authorise("RepsAccess")]

public class RepsController : Controller

{

//

// Index takes multiple parms

public ActionResult Index(string userid=””,string empno=””, string from=””,string to =””)

{

// Load data from web.config & parse into arrays

String RepNamStr = ConfigurationManager.AppSettings["RepNams"];

String RepLnkStr = ConfigurationManager.AppSettings["RepLnk"];

String RepActionsStr = ConfigurationManager.AppSettings["RepActions"];

// Build links for left hand array

string[] RepNamArr = RepNamString.Split(‘~’);

string[] RepLnkArr = RepLnkString.Split(‘~’);

string[] RepActionsArr = RepActionsStr.Split(‘~’);

int arrlen = RepLnkArr.Length;

ViewBag.RepNamArr= RepNamArr;

ViewBag.RepLnkArr = RepLnkArr;

ViewBag.RepActionsArr = RepActionsArr;

ViewBag.Warning = “”;

// Build links for right hand array

String RepNamStringR = ConfigurationManager.AppSettings["RepNamsR"];

String RepLnkStringR = ConfigurationManager.AppSettings["RepLnkR"];

string[] RepNamArrR = RepNamStringR.Split(‘~’);

string[] RepLnkArrR = RepLnkStringR.Split(‘~’);

int arrlenR = RepLnkArr.Length;

ViewBag.RepNamArrR = RepNamArrR;

ViewBag.RepLnkArrR = RepLnkArrR;

Rep myRep = new Rep();

myRep.RepActions = RepActionsArr;

DateTime tempdate;

if (userid != “”)

{

myRep.UserId = userid;

}

if (empno != “”)

{

myRep.EmployeeId = empno;

}

// validate & set from date

if (from == “”)

{

myRep.FromDate = DateTime.Today.AddYears(-1).Date;

}

else

{

if (DateTime.TryParse(from, out tempdate))

{

myRep.FromDate = tempdate;

}

else

{

myRep.FromDate = DateTime.Today.AddYears(-1).Date;

ViewBag.Warning = “A date has been reset to the default”;

}

}

// validate & set to date

if (to == “”)

{

myRep.ToDate = DateTime.Today.Date;

}

else

{

if (DateTime.TryParse(to, out tempdate))

{

myRep.ToDate = tempdate;

}

else

{

myRep.ToDate = DateTime.Today.Date;

ViewBag.Warning = “A date has been reset to the default”;

}

}

return View(myRep);

}

}

}

Create the view  JQuery data validation displays calendar boxes, whose maximum & minimum values are dynamically set according to what has been chosen already:

The ReportAction is a radio button populated from the ReportActions array with a foreach loop

@foreach(var option in Model.ReportActions)

{

@Html.RadioButton(“ReportAction”, option)

@Html.Label(option)

}

( Prefer radio buttons over dropdowns, as it’s a 1 click operation

There is a left list & a right list of report URLS,  The left list is built with an unorderlist ( UL) whose Li elements are populated with an @for loop.   It shows a report name & passes a report URL to the LaunchReport function…

div id=”ReportsLeft”>

<ul>

@for (int i = 0; i < @ViewBag.ReportNameArray.Length; i++)

{

<li><a  onclick=”LaunchReport(‘@ViewBag.ReportLinksArray[i]‘)”>@ViewBag.ReportNameArray[i]</a></li>

}

</ul>

</div>

LaunchReport uses Jquery to get the field values, including the RadioButton

var userID = $(‘#UserId’).val();

.

.

.

var RadioButton = $(“input[name='RadioButtonName']:checked”).val();

@model myMVC_app.Models.Report

@{Html.EnableClientValidation();}

@{

ViewBag.Title = “Reports Menu”;

Layout = “~/Views/Shared/_Layout.cshtml”;

}

<script>

$(function () {

//  Use Jquery ui date picker to provide date ranges that dynamically adjust the max & //minimum available

$(“#FromDate”).datepicker({

dateFormat: “dd/mm/yy”,

onClose: function (selectedDate) {

$(“#ToDate”).datepicker(“option”, “minDate”, selectedDate);

}

});

$(“#ToDate”).datepicker({

dateFormat: “dd/mm/yy”,

onClose: function (selectedDate) {

$(“#FromDate”).datepicker(“option”, “maxDate”, selectedDate);

}

});

});

</script>

<script type=”text/javascript”>

//  Take the url, & add the available parameters to it..

function LaunchReport(reporturl) {

var userID = $(‘#UserId’).val();

var emp = $(‘#EmployeeId’).val();

var from = $(‘#FromDate’).val();

var to = $(‘#ToDate’).val();

var reportaction = $(“input[name='ReportAction']:checked”).val();

var url = reporturl;

if (reportaction != “”) {

url += “&reportaction=” + reportaction.toString();

}

if (userID != “”) {

url += “&userid=” + userID.toString();

}

if (emp != “”) {

url += “&empno=” + emp.toString();

}

if (from != “”) {

url += “&from=” + from.toString();

}

if (to != “”) {

url += “&to=” + to.toString();

}

window.open(url);

}

</script>

<div id=”headpanel”>

<h3>

Reports Menu</h3>

</div>

<div id=”reportdisplaypanel”>

<div id=”reportdisplaycontent”>

<div id=”SearchParm”>

<div id=”ParmList”>

<h3>

Please enter report parameters to use

</h3>

<div>

<div>

@Html.LabelFor(model => model.UserId)

</div>

<div>

@Html.TextBoxFor(model => model.UserId)

@Html.ValidationMessageFor(model => model.UserId)

</div>

</div>

<div>

<div>

@Html.LabelFor(model => model.EmployeeId)

</div>

<div>

@Html.TextBoxFor(model => model.EmployeeId)

@Html.ValidationMessageFor(model => model.EmployeeId)

</div>

</div>

<div>

<div>

@Html.LabelFor(model => model.FromDate)

</div>

<div>

@Html.EditorFor(model => model.FromDate)

@Html.ValidationMessageFor(model => model.FromDate)

</div>

</div>

<div>

<div>

@Html.LabelFor(model => model.ToDate)

</div>

<div>

@Html.EditorFor(model => model.ToDate)

@Html.ValidationMessageFor(model => model.ToDate)

</div>

</div>

<div>

<div>

@Html.LabelFor(model => model.ReportActions)

</div>

<div>

@foreach(var option in Model.ReportActions) {

@Html.RadioButton(“ReportAction”, option)

@Html.Label(option)

}

@Html.ValidationMessageFor(model => model.ReportActions)

</div>

</div>

<div>

@Html.ValidationSummary(true)

@ViewBag.Warning

</div>

</div>

</div>

<h3>

Then click a report below</h3>

<p>

</p>

<div id=”ReportsLeft”>

<ul>

@for (int i = 0; i < @ViewBag.ReportNameArray.Length; i++)

{

<li><a  onclick=”LaunchReport(‘@ViewBag.ReportLinksArray[i]‘)”>@ViewBag.ReportNameArray[i]</a></li>

}

</ul>

</div>

<div id=”ReportsRight”>

<ul>

@for (int i = 0; i < @ViewBag.ReportNameArrayR.Length; i++)

{

<li><a onclick=”LaunchReport(‘@ViewBag.ReportLinksArrayR[i]‘)”>@ViewBag.ReportNameArrayR[i]</a></li>

}

</ul>

</div>

</div>

</div>

WEB API Part 2 invoking csv

Extending the web api with the  results of Mikes additional post  http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters.  ( I had to make some tweaks to get it to work for me  :

Visual studio objected to the definition of  CanReadType &  WriteToStream

I had to use ” public override bool CanReadType”  and “public void WriteToStream(”  instead

In the Index HTML I added the following code

A button in the 2nd div:     <input type=”button” value=”Search csv” onclick=”dumpCSV();” />

& the following Javascript functions :

// dumpCSV to invoke the service call to return the API call as CSV

function dumpCSV() {
var id = $(‘#prodId’).val();
$.ajax({
type: “GET”,
url: “api/products/” + id,
dataType: “text”,
success: function (data) {
successCSV(data);
},
error: function (data) {
errorXML(data);
}});}

successCSV(data) parse the contents of the csv string into variable

function successCSV(data) {

var dataArray = data.split(‘,’);
var Name = dataArray[1];
var Category = dataArray[2];
var Price = dataArray[3];
Name = ReplaceAll(Name,”Name”);
Category = ReplaceAll(Category,”Category”);
Price = ReplaceAll(Price,”Price”);

$(‘#product’).text(“From CSV “+Name + ” (” + Category + “) ” + Price);

}

ReplaceAll is a reusable JavaScript function to strip out all instances of unwanted characters from a string

function ReplaceAll(s,customstring) {
// Gets rid of all instances of unwanted values(“,\,:,{,}) and a customstring) from a string
if (customstring != “”)
{
while (s.indexOf(customstring) != -1) s = s.replace(customstring, ”);
}
// Add new chars to Rep
var Rep = new Array(‘”‘,”\\”,”:”,”{“,”}”);
for (i = 0; i < Rep.length; i++)
{
while (s.indexOf(Rep[i]) != -1) s = s.replace(Rep[i], ”);
}

return s;
}

Mike Wasson’s original article:

Internet Media Types

A media type, also called a MIME type, identifies the format of a piece of data. In HTTP, media types describe the format of the message body. A media type consists of two strings, a type and a subtype. For example:

  • text/html
  • image/png
  • application/json

When an HTTP message contains an entity-body, the Content-Type header specifies the format of the message body. This tells the receiver how to parse the contents of the message body.

For example, if an HTTP response contains a PNG image, the response might have the following headers.

HTTP/1.1 200 OK
Content-Length: 95267
Content-Type: image/png

When the client sends a request message, it can include an Accept header. The Accept header tells the server which media type(s) the client wants from the server. For example:

Accept: text/html,application/xhtml+xml,application/xml

This header tells the server that the client wants either HTML, XHTML, or XML.

In Web API, the media type determines how Web API serializes and deserializes the HTTP message body. There is built-in support for XML, JSON, and form-urlencoded data, and you can support additional media types by writing a media formatter.

To create a media formatter, derive from one of these classes:

  • MediaTypeFormatter. This class uses asynchronous read and write methods.
  • BufferedMediaTypeFormatter. This class derives from MediaTypeFormatter but wraps the asynchronous read/write methods inside sychronous methods.

Deriving from BufferedMediaTypeFormatter is simpler, because there is no asynchronous code, but it also means the calling thread can block during I/O.

Creating a Media Formatter

The following example shows a media type formatter that can serialize a Product object to a comma-separated values (CSV) format. This example uses the Product type defined in the tutorial Creating a Web API that Supports CRUD Operations. Here is the definition of the Product object:

namespace ProductStore.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Price { get; set; }
    }
}

To implement a CSV formatter, define a class that derives from BufferedMediaTypeFormater:

namespace ProductStore.Formatters
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net.Http.Formatting;
    using System.Net.Http.Headers;
    using ProductStore.Models;

    public class ProductCsvFormatter : BufferedMediaTypeFormatter 
    {
    }
}

In the constructor, add the media types that the formatter supports. In this example, the formatter supports a single media type, “text/csv”:

public ProductCsvFormatter()
{
    // Add the supported media type.
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
}

Override the CanWriteType method to indicate which types the formatter can serialize:

public override bool CanWriteType(System.Type type)
{
    if (type == typeof(Product))
    {
        return true;
    }
    else
    {
        Type enumerableType = typeof(IEnumerable<Product>);
        return enumerableType.IsAssignableFrom(type);
    }
}

In this example, the formatter can serialize single Product objects as well as collections of Product objects.

Similarly, override the CanReadType method to indicate which types the formatter can deserialize. In this example, the formatter does not support deserialization, so the method simply returns false.

protected override bool CanReadType(Type type)
{
    return false;
}

Finally, override the WriteToStream method. This method serializes a type by writing it to a stream. If your formatter supports deserialization, also override the ReadFromStream method.

public override void WriteToStream(
    Type type, object value, Stream stream, HttpContentHeaders contentHeaders)
{
    using (var writer = new StreamWriter(stream))
    {

        var products = value as IEnumerable<Product>;
        if (products != null)
        {
            foreach (var product in products)
            {
                WriteItem(product, writer);
            }
        }
        else
        {
            var singleProduct = value as Product;
            if (singleProduct == null)
            {
                throw new InvalidOperationException("Cannot serialize type");
            }
            WriteItem(singleProduct, writer);
        }
    }
    stream.Close();
}

// Helper methods for serializing Products to CSV format. 
private void WriteItem(Product product, StreamWriter writer)
{
    writer.WriteLine("{0},{1},{2},{3}", Escape(product.Id),
        Escape(product.Name), Escape(product.Category), Escape(product.Price));
}

static char[] _specialChars = new char[] { ',', '\n', '\r', '"' };

private string Escape(object o)
{
    if (o == null)
    {
        return "";
    }
    string field = o.ToString();
    if (field.IndexOfAny(_specialChars) != -1)
    {
        return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
    }
    else return field;
}

Adding the Media Formatter

To add a media type formatter to the Web API pipeline, use the Formatters property on the HttpConfigurationobject.

public static void ConfigureApis(HttpConfiguration config)
{
    config.Formatters.Add(new ProductCsvFormatter()); 
}

For ASP.NET hosting, add this function to the Global.asax file and call it from the Application_Start method.

protected void Application_Start()
{
    ConfigureApis(GlobalConfiguration.Configuration);

    // ...
}

Now if a client specifies “text/csv” in the Accept header, the server will return the data in CSV format.

The following example uses HttpClient to get the CSV data and write it to a file:

HttpClient client = new HttpClient();

// Add the Accept header
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv"));

// Get the result and write it to a file.
// (Port 9000 is just an example port number.)
string result = client.GetStringAsync("http://localhost:9000/api/product/").Result;
System.IO.File.WriteAllText("products.csv", result);

End Mike Wasson's original article:
Follow

Get every new post delivered to your Inbox.