Adding CKEditor To an MVC 3 Razor in C# with JQuery

I am creating a web application that will allow content manipulation by end users.  This requires me to insert some sort of editor for them to manage content.  I have used several of these in the past on a few of my ASP.Net sites, but this will the first time in MVC 4 with Razor and its been a few years so I decided to look around.  
I stumbled across CKEdit which is a JQuery based library for a simple HTML editor.  The code seemed laid out well so strapping it on MVC shouldn't be that hard, and it wasn't.  Here are the few steps it took me to get this working well.
1. Download CKEdit from their website.
From here you can even choose the layout you like.  It downloads as a zip file that extracts into a folder you should just place at the root level of your web application.
2. Add the new folder and content to you Project
In VS 2012, you must add each folder then the files in it, sort of annoying you can't add an existing folder, oh well.  Make sure to right click the folder and in properties, set it to always copy to output.  
3. Update your Layout file 
If you want this available on all your web pages do it here, otherwise these just go in the pages you need the editor.  Add or make sure these 3 lines are added in the header.  These include all the Javascript you need to make this happen.
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/ckeditor/ckeditor.js")
@Scripts.Render("~/ckeditor/adapters/jquery.js")
4. Add this function JS Function on the page you want it rendered.
Again, this could be in an include file or in the layout page, or just on the page you need it.
<script type="text/javascript">
    $(function () {
        $('#Content').ckeditor();
    });
</script>
5. Tie your model to the Editor.
So, the above JavaScript function will replace an object with the name content with the ckeditor.  The attribute on my model is named Content, so the id of it will be content, and so the above function finds it and places the editor over it.  I use the following code to generate a text area for it to replace, mostly because a text area is easy to fail to if javascript isn't working.
<div class="editor-label">
            @Html.LabelFor(model => model.Content)
        </div>
        <div class="editor-field">
            @Html.TextAreaFor(model => model.Content)
            @Html.ValidationMessageFor(model => model.Content)
        </div>
6. Update Controller
My controller now needs to be able to land my post with the model.  What is interesting about this is it will throw an error because of possible injection allowing all characters to be posted to the server.  To allow the editor to post the HTML, which it must or it will never render later, you need to put the [ValidateInput(false)] above the function that catches it.  After that, treat it like a string and save it away.
7. Render the saved content.
This should be as easy as just @Object.Field however it isn't of course.  MVC is smarter than us, and html encodes any string rendered so all tags will show up.  What we have to do instead is @Html.Raw(Object.Field) and everything will look great.  
8 Have Fun!

Shipping Girth Calculations in C#

I recently had to calculate girth in a shipping sense which isn't very exciting.  It requires you to take the length, width, and height of the object and use the following equation.  Longest Side + 2*(Middle Side + Shortest Side).  
I would like to do this in a line of code, but alas, determining which of the 3 variables is longest makes this a if else type problem.  Here is my solution, I thought it rather nice, though I'm sure more memory is used and it compiled larger than a simple if else setup, but I think it reads nicer.

var sl = new List<double>() { Length, Width, Height };
var Girth = sl.Max() + 2 * sl.OrderBy(c=>c).ToList()[1] + 2 * sl.Min();

The use of a List allows some macro functions like Max and Min, and I can use the .orderby function and some lambda to index through and get the middle sized item.

WCF ws-Security and SoapUI

So recently I talked about ws-Security Headers with WCF.  http://www.ghij.org/blog/post/2014/04/01/username-wssecurity-header-with-wcf.aspx  But today I ran into the problem of trying to test said service locally.  I like to use soapUI which is a great tool.  The problem I ran into was it kept failing saying with the error BadContextToken from WCF.  Some time on google showed this is a common problem with SoapUI connecting to WCF with the UserName security type. 
In order to still get my testing done, I ended up creating a second endpoint with its own binding to do testing with SoapUI. Obviously you wouldn't release this for the security hole it creates, but locally and on dev, it allows you nice debugging of the service with SoapUI.
1. Create the new endpoint (next to the old one)
<endpoint
					address ="soapService"
					binding ="wsHttpBinding"
					contract="PPMRK_PLMService.IPLMService"
          bindingConfiguration="tcpWithMessageSecurity"
					/>
<endpoint
					address ="soapUIService"
					binding ="wsHttpBinding"
					contract="PPMRK_PLMService.IPLMService"
          bindingConfiguration="tcpWithMessageNoSecurity"
					/>
2. Then Add the new binding configuration for the new endpoint.
<binding name="tcpWithMessageSecurity">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
        <binding name="tcpWithMessageNoSecurity">
          <security mode="None">
            <transport clientCredentialType="None" />
            <message establishSecurityContext="false" />
          </security>
        </binding>
3. Fix SoapUI 
Now you can configure SoapUI, bind to the wsdl as you would. In the request, click the WS-A tab at the bottom and check the add default wsa:action and Add default wsa:To boxes. 
4. Profit!

UserName ws-Security Header with WCF

If you work with web services for customers to call, security has to be a top priority.  The Soap protocol has something called the ws-Security Header which you can read more about here http://msdn.microsoft.com/en-us/library/ms977327.aspx.  Now WCF can be configured about infinite different ways.  What I wanted to do was just make a simple Username Password passed in the header of the service call over https.  From what I have gathered, this is the best way to do it in WCF.

1. Configure your web.config. 

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <services>
      <service name="PPMRK_PLMService.PLMService" behaviorConfiguration="CustomValidator">
        <endpoint
					address ="soapService"
					binding ="wsHttpBinding"
					contract="PPMRK_PLMService.IPLMService"
          bindingConfiguration="tcpWithMessageSecurity"
					/><baseAddress><add baseAddress="http://localhost/PLMService" /></baseAddress>
      </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <binding name="tcpWithMessageSecurity">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CustomValidator">
          <serviceMetadata httpGetEnabled="true">
            <serviceCredentials>
            <userNameAuthentication
              userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="PPMRK_PLMService.Authentication.CustomUserNameValidator, PPMRK_PLMService"/>
            <serviceCertificate
              findValue="localhost"
              x509FindType="FindBySubjectName"
              storeLocation="LocalMachine"
              storeName="My" />
          </serviceCredentials>
        </behavior>
          <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="false" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

You can see this isn't a stock config file, well hopefully you can.  Inside the system.serviceModel tags, I added services tags, a new behavior and bindings to get this to work.  The service is declared explicitly to bind to the new behavior called CustomValidator as well as declare the endpoint with a tcpWithMessageSecurity bindingConfiguration. 

Next, the bindings gets a new netTcpBinding what has a message security mode with a clientCredentialType of Username. This will make it use a username password header type.

Finally, The new behavior added I call CustomValidator binds the authentication of the username password to a custom class I wrote (below) and a certificate I have installed (how to below further).

2. Create the Authentication Class

public class CustomUserNameValidator : UserNamePasswordValidator
    {

        public override void Validate(string userName, string password)
        {

            if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))

                throw new SecurityTokenException("Username and password required");

            if (true)//validate

                throw new FaultException(string.Format("Wrong username ({0}) or password ", userName));

        }

    }

This class simply implements the UserNamePasswordValidator (System.IdentityModel.Selectors) class's Validate function.  Not hard.

3. Create Cert (for Dev to Start)

What you need to do here is fire up the Visual Studios Command Prompt (http://msdn.microsoft.com/en-us/library/ms229859(v=vs.110).aspx) and use the makecert function to create a cert to test with.  (http://msdn.microsoft.com/en-us/library/ms733813.aspx).  I ran my make cert like this.

makecert -sv C:\temp\Sign_Root2.pvk -cy authority -r C:\Temp\Sign_Root2.cer -a sha1 -n "CN=Dev Cert Authority2" -ss my -sr localmachine

I had to run this as administrator, or I got errors, so keep that in mind. 

4. Install the Dev Cert

This can easily be done by right clicking and installing the .cer file you created.  Note my cert goes to local machine.  You may need to run certmgr.msc or mmc as a local admin and give rights to the cert to your main account for it to work correctly. 

5. You should be able to run your service and see the wsdl, it now has ws-Security Header stuff installed.

Google Charts API in MVC C#

So I saw the new Google Charts API and decided it would be interesting to play with.  I had played with it 5 years ago or so when it first came out, and it has come a long way.  The developer documentation seems solid to work from, and its just javascript so it can't be that hard.  Plus, even if the doc isn't 100% easy to understand, any example they have is basically open source via view source, so you can easily figure out a lot.  The piece I was really after was the sliding bar to restrict ranges, it took a while, and was worth it.  I also added some cool functionality like clicking a data set in the legend and having it disappear.
I decided to embed it in MVC as that's the technology my current job has me using the most.  I wanted to make a generic wrapper in MVC for the Charts API so I could take any data set and throw it at any chart on the fly and see the different charts, without changing code.  Turned out rather awesome, though it doesn't work the best in IE always, Chrome is much more consistent.
So here we go, the first thing I will show is the nuts and bolts of the entire project, the one view that has all the javascript in it.  I will try to discuss the pieces here as there is a lot going on.
@model PPCOP_OrderProcessingReports.Models.ReportFetcher
@{
    ViewBag.Title = "Report";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.0','packages':['controls']}]}"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);

      function drawChart() {
          var rawdata = @Html.Raw(Model.OrdersForGoogleChart())
          var data = google.visualization.arrayToDataTable(rawdata);

          $("#chart_div").empty();
          $("#chart_div").html('<div id="scatterchart_div"></div>' +
          '<div id="filter_div"></div>');

          var dashboard = new google.visualization.Dashboard(
            document.getElementById('chart_div'));

          var rangeSlider = new google.visualization.ControlWrapper({
              'controlType': 'NumberRangeFilter',
              'containerId': 'filter_div',
              'options': {
                  'filterColumnLabel': 'Range',
                  'ui.labelStacking': 'vertical',
                  'ui.showRangeValues': false
              }
          });

          // create columns array
          var columns = [];
          var series = {};
          for (var i = 0; i < data.getNumberOfColumns() ; i++) {
                  columns.push(i);
                  if (i > 0) {
                      // set the default series option
                      series[i - 1] = {};
                  }
          }

          var options = {
              width: '100%',
              height: 300,
              title: '@Html.Raw(Model.DataName)',
              legend: '',
              lineWidth: 1,
              hAxis: { title: '@Html.Raw(Model.LegendHAxis)' },
              vAxis: { title: '@Html.Raw(Model.DataName)' },
              pointSize: 1,
              series: series
          };

          var chart = new google.visualization.ChartWrapper({
              //'chartType': 'ScatterChart',
              //'chartType': 'LineChart',
              'chartType': '@Html.Raw(Model.ChartType)',
              'containerId': 'scatterchart_div',
              'options': options,
          });

          dashboard.bind(rangeSlider, chart);
          dashboard.draw(data);

          google.visualization.events.addListener(chart, 'ready', function () {
              google.visualization.events.addListener(chart.getChart(), 'select', function () {
                  var sel = chart.getChart().getSelection();
                  // if selection length is 0, we deselected an element
                  if (sel.length > 0) {
                      // if row is undefined, we clicked on the legend
                      if (sel[0].row == null) {
                          var col = sel[0].column;
                          //if (columns[col] == col) {
                          if (columns[col] == col) {
                              // hide the data series
                              columns[col] = {
                                  label: data.getColumnLabel(col),
                                  type: data.getColumnType(col),
                                  calc: function () {
                                      return null;
                                  }
                              };

                              // grey out the legend entry
                              series[col - 1].color = '#CCCCCC';
                          }
                          else {
                              // show the data series
                              columns[col] = col;
                              series[col - 1].color = null;
                          }
                          var view = new google.visualization.DataView(data);
                          view.setColumns(columns);
                          chart.getChart().draw(view, options);
                      }
                  }
              })
          });

          var table = document.createElement('table');
          $("#data_div").empty();
          var dataoutput = "<table style='width:100%;text-align:center;border: 1px solid black;'>";
          for(var x = 0; x < rawdata.length; ++x)
          {
              dataoutput += "<tr style='border: 1px solid black;'>";
              for(var y = 0; y < rawdata[0].length; ++y)
              {
                  dataoutput += "<td style='border: 1px solid black;'>"+rawdata[x][y]+"</td>";
              }
              dataoutput += "</tr>";
          }
          $("#data_div").html(dataoutput+"</table>");
      }
    </script>
    @using (Html.BeginForm()) {
        @Html.ActionLink("Load Data", "LoadData")
        @Html.ValidationSummary(true)
        <table>
            <tr>
        <td>Select Brand
        @Html.DropDownListFor(x=>x.BrandId, new SelectList(ViewBag.Brands,"Id","Name"))</td>
        <td>Select Time Buckets
        @Html.DropDownListFor(x=>x.TimeSpanId, new SelectList(ViewBag.TimeSpans,"Id","Name"))</td>
        <td>Select Source
        @Html.DropDownListFor(x=>x.SourceId, new SelectList(ViewBag.Sources,"Id","Name"))</td>
        <td>Select Data
        @Html.DropDownListFor(x=>x.DataId, new SelectList(ViewBag.DataTypes,"Id","Name"))</td>
        <td>Select Chart Type
        @Html.DropDownListFor(x=>x.ChartType, new SelectList(ViewBag.ChartTypes,"Name","Name"))</td>
                <td>Align Weeks (only on days)
        @Html.CheckBoxFor(x=>x.AlignWeeks)</td>
        <td><input type="submit" value="Update" /></td>
                </tr>
        </table>
    }
<br />
<div id="chart_div" style="width:100%; height:330px"></div>
The first thing to note is the included files.  Jquery 1.71, and two jsapi includes from google which give the chart api.  
The next thing to note is the javascript I wrote.  the first things done are the loading of the google objects.  After that the drawChart() function is created and it is invoked by the google.setOnLoadCallBack event.
The drawChart function is the nuts and bolts of the chart drawing.  What I do is pass the data to google via a two dimensional array that I construct in a class in my mvc from some database.  It is in simple [[1,1,1],[1,1,1]] structure.  Note I had to pass the semicolon from c# as razor was throwing a fit about it in the JavaScript behind the server tag.  
Once the data is loaded, google has a good function called arrayToDataTable that converts it on the fly to the correct data table type.  Next a few html operations are done in jquery to get the correct spot to dump the chart.  This is also where my range slider is declared and tied to the range of the data set.
After that I create column arrays.  This is needed for my hiding functionality.  Basically, I store the columns of the data set and if they are clicked in the legend, I hide them.  This is done lower in the code under the addlisteners on ready and select below the dashboard bind and draw.
The actual drawing of the chart is in the call ChartWrapper, it takes in the options object declared before it.  This is where I pass in the axis and title dynamically to draw the chart.  The chartWrapper call takes in chart type dynamically you can see, these are all controlled from the model, and influenced by the drop down lists you see at the bottom of the html page.
Next, I will show you the controller code.
public ActionResult Report()
        {
            var ctx = new PPCOPDataDataContext();
            ViewBag.Brands = (from a in ctx.tbl_Brands select a).OrderBy(c=>c.Name).ToList();
            ViewBag.TimeSpans = (from a in ctx.tbl_TimeSteps select a).OrderBy(c => c.Name).ToList();
            ViewBag.Sources = (from a in ctx.tbl_Sources select a).OrderBy(c => c.Name).ToList();
            ViewBag.DataTypes = (from a in ctx.tbl_SourceNames where a.SourceId == 0 select a).OrderBy(c => c.Name).ToList();
            ViewBag.ChartTypes = GetChartTypes();
            return View(new Models.ReportFetcher() { BrandId = 17, DataId = ViewBag.DataTypes[0].Id, DataName = ViewBag.DataTypes[0].Name, ChartType="ScatterChart", LegendHAxis = this.LegendHAxis.Split('|')[0] });
        }
        [HttpPost]
        public ActionResult Report(Models.ReportFetcher fetcher)
        {
            var ctx = new PPCOPDataDataContext();
            ViewBag.Brands = (from a in ctx.tbl_Brands select a).OrderBy(c => c.Name).ToList();
            ViewBag.TimeSpans = (from a in ctx.tbl_TimeSteps select a).OrderBy(c => c.Name).ToList();
            ViewBag.Sources = (from a in ctx.tbl_Sources select a).OrderBy(c => c.Name).ToList();
            ViewBag.DataTypes = (from a in ctx.tbl_SourceNames where a.SourceId == fetcher.SourceId select a).OrderBy(c => c.Name).ToList();
            ViewBag.ChartTypes = GetChartTypes();
            if (!(ViewBag.DataTypes as IList<tbl_SourceName>).Any(c => c.Id == fetcher.DataId))
            {
                fetcher.DataId = ViewBag.DataTypes[0].Id;
                fetcher.DataName = ViewBag.DataTypes[0].Name;
            }
            else
            {
                fetcher.DataName = (ViewBag.DataTypes as IList<tbl_SourceName>).Where(c => c.Id == fetcher.DataId).First().Name;
            }
            fetcher.LegendHAxis = this.LegendHAxis.Split('|')[fetcher.TimeSpanId];
            return View(fetcher);
        }

        public IList<ChartTypes> GetChartTypes()
        {
            var returner = new List<ChartTypes>();

            returner.Add(new ChartTypes() { Name = "ScatterChart" });
            returner.Add(new ChartTypes() { Name = "AreaChart" });
            returner.Add(new ChartTypes() { Name = "LineChart" });
            returner.Add(new ChartTypes() { Name = "Histogram" });
            returner.Add(new ChartTypes() { Name = "ColumnChart" });
            returner.Add(new ChartTypes() { Name = "BarChart" });
            returner.Add(new ChartTypes() { Name = "ComboChart" });

            return returner;
        }
You can see I have the Report get and post functions plus a getcharttypes function.  Things to note in here are me just constructing my model and returning it.  The get is all defaults and drop down populations with simple lists.  The GetChartTypes is an example of a function to return a list of types to put in a drop down list.  They are simply the names that google gave them so I can pass them straight to the dashboard object in javascript, real easy.  My post method gets the drop down selections and updates the model and responds it to update the chart.  
The last piece is the code that generates the array list.  It comes from a class called Report Fetcher you can see.  I obviously could extract that better but this is rather specific for the program so I didn't take it that far, though one could and create a very generic class that anyone could reuse.  I am not going to share that code as it ties in a lot of business logic now, but your just constructing a 2 dimensional array, not rocket science.  
Looking back, I should mention the checkbox that aligns days.  I was displaying order data here, and I wanted to line weeks up by day of week from the previous year, so I created a table of year offsets to line up thanksgiving day and offset all days of the year.  This allows us to view our order history from previous years for the same weeks, it works well.