Wednesday, October 12, 2011

RAZOR cascading DropDownList

RAZOR


@Html.DropDownList("ddlElementCode",
TempData["ElementSelects"] as SelectList,
new { onchange = "populateValueTexts(this)" })




// Where the parameter “dropdown” is the first of the two

function populateValueTexts(dropdown) {
var myindex = dropdown.selectedIndex;
var selValue = dropdown.options[myindex].value
var xReq = jQuery.getJSON("ElementTexts",
{ elementCode: selValue },
null)
.complete(receiveValueTexts);
}

function receiveValueTexts(context, textStatus) {
var data = jQuery.parseJSON(context.responseText);

document.getElementById("ddlValueText").options.length = data.length;

jQuery.each(data, function (i, item) {
document.getElementById("ddlValueText").options[i].text = item.Text;
});
}

[AcceptVerbs(HttpVerbs.Get)]
public JsonResult ElementTexts(string elementCode)
{
Data d = new Data();

IList codes =
d.GetElementsByCode(Convert.ToInt32(elementCode));

SelectList items =
new SelectList((from c in codes select c.ELEMENT_VALUE_TXT).Distinct());

return Json(items, JsonRequestBehavior.AllowGet);
}

Tuesday, October 04, 2011

On getting NHibernate to Log the SQL

This feature is very nice. You get to see the SQL that is generated for you.

While logging is not rocket science, I don't want to learn it again on the next project, so I am saving it here. ( I am using Log4Net, but I am sure Enterprise Library or others will work similarly. )

// Configure log4net using the .config file in GLOBAL.ASAX
[assembly: XmlConfigurator(Watch = true)]
protected void Application_BeginRequest(object sender, EventArgs e)
{
XmlConfigurator.Configure();
}

In the Web.config

<log4net debug="true">
<!-- Define some output appenders -->
<appender name="trace" type="log4net.Appender.TraceAppender, log4net">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n"/>
</layout>
</appender>
<appender name="console" type="log4net.Appender.ConsoleAppender, log4net">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n"/>
</layout>
</appender>
<appender name="rollingFile" type="log4net.Appender.RollingFileAppender,log4net">
<param name="File" value="hib_log.txt"/>
<param name="AppendToFile" value="true"/>
<param name="maximumFileSize" value="500KB"/>
<param name="RollingStyle" value="Size"/>
<param name="DatePattern" value="yyyy.MM.dd"/>
<param name="StaticLogFileName" value="true"/>
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/>
</layout>
</appender>
<!-- Setup the root category, add the appenders and set the default priority -->
<root>
<priority value="DEBUG"/>
<appender-ref ref="rollingFile"/>
</root>
<logger name="NHibernate">
<level value="WARN"/>
</logger>
<logger name="NHibernate.SQL">
<level value="DEBUG"/>
</logger>
</log4net>

Monday, October 03, 2011

How to stream a File in MVC

In Classic ASP or ASP .Net, you can simply change the response type and start writing binary. In MVC you have a Controller method which returns an ActionResult. So this class will properly provide that :


public class BinaryResult : ActionResult
{
private byte[] _fileBinary;
private string _contentType;
private string _fileName;

public BinaryResult(byte[] fileBinary, string contentType, string fileName)
{
_fileBinary = fileBinary;
_contentType = contentType;
_fileName = fileName;
}

public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.ContentType = _contentType;
context.HttpContext.Response.AddHeader("Content-Disposition",
"filename=" + _fileName);

if (_fileBinary != null)
{
context.HttpContext.Response.BinaryWrite(_fileBinary);
}
}
}


In my case the only other challenge was getting the Byte array prepared, because I had to call Convert.FromBase64String, because of the way the data was stored.

Sunday, October 02, 2011

Developing for MVC4 using Razor and JSON

Just playing around this weekend, I wanted some data listings in a page that did not post back in MVC. While not such a big deal in regular ASP, MVC does not have page event handlers in a code-behind file. There is instead a Controller class that you can call in Routing code.



First : the client side javascript handler, this is what is called when the Controller method completes.



using (Ajax.BeginForm("SearchForms", "DBForms", new AjaxOptions() { OnSuccess="jsonFSearchComplete", OnFailure="searchFail" })) Then … function jsonFSearchComplete(context) { $("#DBFormsDiv").html(context.Data); }



Next, the Razor syntax for the page :


@{using (Ajax.BeginForm("JsonSearchRequests",
"Request",
new AjaxOptions() {
OnComplete = "searchComplete",
OnFailure= "searchFail"
}))

// Not including the whole form I created here, just
// labels and textboxes, etc..
}





Then the Controller code for getting the Partial view built and sent down (Got this from StackOverflow postings):


private string RenderRazorViewToString(string viewName)
{
using (var sw = new System.IO.StringWriter())
{
var viewResult =
ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
var viewContext =
new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}


For a form posting in a page, there must be a Controller method ( :


[AcceptVerbs(HttpVerbs.Post)]
public JsonResult JsonSearchRequests(string AccountNumber,
string Subfirm,
string RegistrationType)
{
Data d = new Data();

if (AccountNumber.Length > 0)
{
ViewData["Requests"] =
d.GetRequestsByAccount(AccountNumber);
}
else if (Subfirm.Length > 0)
{
ViewData["Requests"] =
d.GetDBRequests(Subfirm, RegistrationType)
.Skip(0).Take(100);
}
return Json(new { Data = RenderRazorViewToString("dbRequests") });
// Note the HttbVerb must be stated for Posting a form
}


For a link that a user can click in the page :



[AcceptVerbs(HttpVerbs.Get)]
public JsonResult JsonSelectDbRequest(string Id)
{
Data d = new Data();
ViewData["Generations"] = d.GetGenerations(Id);

return Json(new { Data = RenderRazorViewToString("dbGenerations") },
JsonRequestBehavior.AllowGet);
}

// Note the Http Verb for GET must be stated
}



Code for a Partial View of a list that does Ajax posting :


@Ajax.ActionLink("SELECT",
"JsonSelectDbRequest",
"DocRequest",
new { Id = req.REQUEST_ID },
new AjaxOptions() { OnComplete = "requestSelectComplete" });



EDIT: There is no need to include the old MVCAjax script files.

Saturday, September 10, 2011

Generics For Dummys (re:NHibernate)

I am working on a rogue project that is not being paid for by the company for which I work. This is building something that just helps me do my job, so I have to be very quick. I am using NHibernate, and wanted to get listable data without writing even the smallest functions of my own. So I created this (not for production use):

   public IList GetAll()
        {                     
            return Session.GetSession()
            .CreateCriteria(typeof(T))
            .List();
         }


Because NHibernate uses generics, this function can act as a pass-through, requesting the List method be run, but not much more. My ASP .NET webforms application has to give it the table name of interest.

Again, just a fun way to rapidly get a "table viewer" application running but also providing some code value for potential full life cycle development later.

* Re-reading years later, I think I meant
 GetAll(T) 
as the Type would have to be passed to the function.

Text Template Transformation

My team stores some database logic in an XML file that is part of a CSharp project.
This seems to be working efficiently for the application in runtime and for developers to maintain their SQL statements at design. I don't like it because the file has gotten large and finding things is a manual process.
I am trying to keep up with innovations, so I wrote a transformation that changes that XML file into a class. That way Visual Studio can provide its drop-down navigation controls for finding statements in the file.


<#@ template language="C#" #>
<#@ output extension = "cs" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace = "System.Xml" #>


public class SQLConfig {
<#
XmlDocument doc = new XmlDocument();
doc.Load("C:\\Projects\\MySolution\\MyDataLayer\\ORACLESQL.config");

foreach(XmlNode node in doc.SelectNodes("//add")) {

#>

public const string <#= node.Attributes[0].Value.Replace(".","_").Replace("-","_") #> = @"<#= node.InnerText #>";

<#
}

doc = null;
#>
}



What this does is create a Class file using the above code every time the transform template is changed, or the developer can right-click "Run Custom Tool" on it.

Wednesday, August 24, 2011

Developing for Oracle

Since I have seen a lot of hand-wringing over how to write a connection string to Oracle Express, I want to save a note about this.


(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=Me;Password=dev;


This is just one of those things, that as a programmer I don't know how to build when I need it. It's a bit of technical stuff that I don't endeavor to deeply understand.