The following link should actually be an embedded twitter feed using their timeline widget. Sadly, so far, it is not. Checking the network traffic just reveals an error from their service stating that it "Unable to load timeline", with a status of 503. Gah.
Tweets by @HannesNA blog touching on topics such as technical code solutions (or problems) and software development processes.
Wednesday, August 21, 2013
Sunday, February 17, 2013
Work for Intergen and Microsoft at NRF 2013
I recently finished up a post about some work our company did for Microsoft at the 2013 NRF show. It was a fascinating project, and I was compelled to write a bit more about it on the company blog. Read all about it here, and also watch the youtube video.
As an aside, how weird does it make me to prefer typing this blog in raw html, rather than using the wysiwyg editor option, which spits out terrible html? Hmmm...
Thursday, June 28, 2012
Reading file content using DataReader.ReadBytes in Metro apps
The Windows.Storage.Streams.DataReader.ReadBytes method stupidly breaks with the convention of the other methods on the DataReader object, by requiring you to pass in a variable to populate, instead of instantiating a new variable and returning it.
Looking at the declaration of this method:
[MethodImpl] void IDataReader.ReadBytes([Out] byte[] value);we see that the value is marked with an Out attribute. Note that this is not the same as an out parameter modifier.
To have your passed in value correctly populated, you need to instantiate the byte array to pass in, using the correct capacity. The capacity is available on your reader in the UnconsumedBufferLength property.
Here's a sample of using this method:
StorageFile file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync("[filename]");
IBuffer buffer = await FileIO.ReadBufferAsync(file);
DataReader reader = DataReader.FromBuffer(buffer);
byte[] fileContent = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(fileContent);
Thursday, June 21, 2012
Deserialising a JSON formatted string to a dynamic object in C# Metro Style Apps
I found myself looking for an easy way to deserialise Json strings to dynamic objects today. Of course there are many excellent libraries (like Json.net) that will already do this for you. The problem is that I need to do it in a Metro Style app, which can't reference regular .Net libraries.
So, what to do?
First off, Json Serialisation has been provided as a first class citizen in Metro Style apps. There's no point in doing that again. We will use the Windows.Data.Json.JsonObject class provided in WinRT. Where our paths diverge from this provided class, is that the objects are accessed in a relatively gnarly way:
JsonObject jsonObject = JsonObject.Parse(jsonString); string myStringProperty = jsonObject["myStringPropertyName"].GetString(); double myDoubleProperty = jsonObject["myDoublePropertyName"].GetNumber();There are different methods you call depending on the type of the value you want. This type is exposed in the ValueType property of the IJsonValue interface, which is the type of the object returned by the indexing operation. We don't necessarily like this.
What I want to do is to read my Json object like this:
dynamic jsonObject = new DynamicJsonObjectReader(jsonString); string myStringProperty = jsonObject.myStringPropertyName; double myDoubleProperty = jsonObject.myDoublePropertyName;It's debatable wether we would want the property to be returned as a concrete type, or as a dynamic object, but for these purposes I want a concrete type for string, double, bool and Array, and another DynamicJsonObjectReader for JsonObject.
To accomplish this, I created an object that wraps up the built-in JsonObject class and inherits from DynamicObject. I called the object a reader, because I've only overridden the TryGetMember method. To make it writable, I would also override the TrySetMember method. This is a bit more complicated, and surplus to my needs. For Now. The ToString method will spit out the Json formatted representation, which at the moment is useful for debugging. Once TrySetMember is properly implemented, ToString would be used for serialising. Here is the code:
Update:I've added an implementation for GetDynamicMemberNames. This enables the debugger to show you all the members and their values at runtime in the watch window. Pretty handy.
using System;
using System.Dynamic;
using System.Linq;
using Windows.Data.Json;
namespace JsonSerialisation
{
internal class DynamicJsonObjectReader : DynamicObject
{
private readonly JsonObject jsonObject;
public DynamicJsonObjectReader(string jsonString)
{
jsonObject = JsonObject.Parse(jsonString);
}
private DynamicJsonObjectReader(JsonObject jsonObject)
{
this.jsonObject = jsonObject;
}
public override string ToString()
{
return jsonObject.Stringify();
}
public override IEnumerable GetDynamicMemberNames()
{
return jsonObject.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
IJsonValue jsonValue;
if (!jsonObject.TryGetValue(binder.Name, out jsonValue))
{
// return null to avoid exception. caller can check for null this way...
result = null;
return true;
}
result = GetValue(jsonValue);
return true;
}
private object GetValue(IJsonValue jsonValue)
{
object result = null;
switch (jsonValue.ValueType)
{
case JsonValueType.Object:
result = new DynamicJsonObjectReader(jsonValue.GetObject());
break;
case JsonValueType.String:
result = jsonValue.GetString();
break;
case JsonValueType.Number:
result = jsonValue.GetNumber();
break;
case JsonValueType.Boolean:
result = jsonValue.GetBoolean();
break;
case JsonValueType.Array:
result = CreateArray(jsonValue.GetArray());
break;
}
return result;
}
private Array CreateArray(JsonArray jsonArray)
{
return jsonArray.Select(GetValue).ToArray();
}
}
}
Tuesday, June 12, 2012
Enabling PIN authentication on Windows 8 for domain logons
By default, PIN authentication is disabled for domain logons on Windows 8 Release Preview.
There is a new group policy setting for allowing pin authentication. The description reads:
This policy setting allows you to control whether a domain user can sign in using a PIN. If you enable this policy setting, a domain user can set up and sign in with a PIN. If you disable or don't configure this policy setting, a domain user can't set up and use a PIN. Note that the user's domain password will be cached in the system vault when using this feature.
The setting is located by running GPEdit.msc Then navigate to Computer Configuration -> Administrative Templates -> System -> Logon -> Turn on pin sign-in Set this setting to enabled to allow domain users to use a pin when signing in to the computer.
Tuesday, May 15, 2012
How to determine the username of the logged on user in Windows 8 Metro Style apps
There are 2 options available here, depending on what you would like to achieve.
If it's simply to authenticate a user, you would want to use the Windows.Security.Authentication.Web.WebAuthenticationBroker, and one or more OAuth2.0 identity services like Facebook or Windows Live. There are very good samples available on using these. Start with MSDN
If you need to do authorization or log a user in using a web service, you may need to know the logged in user's username. This can be found in the UserInformation object, like so:
Windows.System.UserProfile.UserInformation.getPrincipalNameAsync().then(function (result)
{
Debug.writeln(result);
});
You can then look at using the various web services and APIs provided by your chosen identity provider. One option is to provide your own web service, which may perform any further required logging in for the user, if Kerberos is not working for you.
Another option when having to ask the user for credentials is to use the CredentialPicker object. Here's an example of how to use it:
var credentialPickerResults; var credentialPickerOptions = new Windows.Security.Credentials.UI.CredentialPickerOptions(); credentialPickerOptions.targetName = "My App"; credentialPickerOptions.caption = "My App"; credentialPickerOptions.message = "Sign in to My App"; credentialPickerOptions.authenticationProtocol = Windows.Security.Credentials.UI.AuthenticationProtocol.ntlm; credentialPickerOptions.alwaysDisplayDialog = false; var credentialPicker = Windows.Security.Credentials.UI.CredentialPicker; credentialPicker.pickAsync(credentialPickerOptions).done( function complete(result) { console.log("pickAsync complete: username = " + result.credentialUserName + ", password = " + result.credentialPassword + " errorCode = " + result.errorCode); credentialPickerResults = result; }, function error(e) { console.log("pickAsync error: " + e.message); }); The result object will contain the credentials the user specified. No authentication is performed on these credentials.Tuesday, May 8, 2012
Displaying your product version in a Windows 8 Metro App
When creating a package for the store, the wizard gives you an option to automatically increment the package version number. This version number is used for a variety of important things. Wouldn't it be useful to display this number to the user when doing support, or logging errors?
To access the version you can easily use
Package.Current.Id.Version;This returns a PackageVersion, with the regular 4 version properties.
Format it like so:
PackageVersion packageVersion = Package.Current.Id.Version;
string.Format("{0}.{1}.{2}.{3}", packageVersion.Major, packageVersion.Minor, packageVersion.Build,packageVersion.Revision);
Extra points for turning this into an extension method if you'll be doing it in more than one place!
In my current app, I've decided to add it to the application resources, and then bind to it from wherever I want to display it.
Windows App Certification Kit Test can't find the app
I've been trying to run the Windows App Certification Kit Test for a while now and again after building a package. It failed every time with an error stating that it couldn't find the app. I found this rather strange, because whenever I open the start menu, it's right there!
It turns out, before you run the kit, you have to install the package. When Visual Studio deploys the app, it is deployed as an unpackaged app. The certification kit looks for a packaged app, with a particular application name (a product guid). I won't go into the details about the other differences.
First, you have to uninstall the unpackaged app that Visual Studio deploys. Right click on the app in the start menu, and click Uninstall in the app bar.
To install the app, click on the link to the build package location in the window that is displayed after package creation. Next, open the folder with the name of your package, right click the Add-AppxDevPackage.bat file, and click Run as administrator. This will install your app as a packaged app.
You can now click the button to run the certification kit.
Sunday, May 6, 2012
COM Exception "HRESULT E_FAIL has been returned from a call to a COM component" in C# Windows 8 Metro app
I've recently been developing a few Windows 8 apps using the Consumer Preview release of Windows 8 and VS11. For the last week I've been struggling with a bug that occurred in a Windows 8 C#/XAML app.
In my app I have a Hub Page, which displays a grid with grouped items. I bind this grid to a CollectionViewSource, which takes care of this grouping for me. I also have a snapped view, which uses a ListView bound to the same CollectionViewSource. I got a ComException intermittently whenever I navigated to the page in the Snapped view. No exception would occur when navigating around in the filled view.
The exception would only be reported as a System.Runtime.InteropServices.COMException, with the message "Error HRESULT E_FAIL has been returned from a call to a COM component." and the error code -2147467259
I thought for a long time that it was a syncronisation problem on the ObservableCollection I was binding to, as I had several threads updating this collection. The problem only occurred when I was replacing items in the collection.
Eventually, the fact that it was only occurring in the snapped View, made me question what the difference was between the two. The only meaningful difference was that they never showed at the same time, and the snapped view was bound to the CollectionViewSource after the first. I remembered noticing in a different article about ObservableCollection that there could be problems binding multiple UIElements to the same collection, so this made me have another look at the XAML. My first attempt was to create a copy of the CollectionViewSource for my snapped view, and change the binding for the ListView.
It worked! I almost ran naked down the street!
I have no idea why it wouldn't work previously, but I can only speculate that the filled GridView may be taking too long to render the individual items, as the process to do so is actually quite involved in this instance. Using 2 identical CollectionViewSources is less efficient, but seems to be a sad necessity this time around.
Wednesday, February 15, 2012
T-SQL for killing active connections to your database
USE master GO SET NOCOUNT ON DECLARE @DBName varchar(50) DECLARE @spidstr varchar(8000) DECLARE @ConnKilled smallint SET @ConnKilled=0 SET @spidstr = '' Set @DBName = 'DB_NAME' IF db_id(@DBName) < 4 BEGIN PRINT 'Connections to system databases cannot be killed' RETURN END SELECT @spidstr=coalesce(@spidstr,',' )+'kill '+convert(varchar, spid)+ '; ' FROM master..sysprocesses WHERE dbid=db_id(@DBName) IF LEN(@spidstr) > 0 BEGIN EXEC(@spidstr) SELECT @ConnKilled = COUNT(1) FROM master..sysprocesses WHERE dbid=db_id(@DBName) END
Sunday, November 13, 2011
Programmatically printing CRM SSRS reports.
http://social.msdn.microsoft.com/Forums/en-US/sqlreportingservices/thread/b704d524-09a2-43b3-b4f3-708b8def4dea
https://connect.microsoft.com/SQLServer/feedback/details/560911/sql-2008-r2-reportexecutionservice2005-broken-with-image-emf
http://social.msdn.microsoft.com/Forums/en-SG/sqlreportingservices/thread/e3367f6a-e76d-4567-bd11-dafe5a3b2a5a
I have updated the code samples in this article to reflect the new approach.
We recently had to create a service to programmatically print some CRM 2011 reports hosted with SSRS on SQL 2008 R2. Our solution involves using the SSRS execution service to render the report, and then printing it using the System.Graphics.PrintDocument class.
This tutorial on the MSDN website shows the steps required to render reports in any supported format:
http://msdn.microsoft.com/en-us/library/ms154699.aspx
Here is a short post by someone else on rendering reports: http://geekswithblogs.net/stun/archive/2010/02/26/executing-reporting-services-web-service-from-asp-net-mvc-using-wcf-add-service-reference.aspx
SSRS exposes five services. The services called ReportService2005 and ReportService2006 have been deprecated and rolled into ReportService2010 service. This is not the service you want. This service is for server management. A seperate service called ReportExecution2005, located at http://{servername}/ReportServer/ReportExecution2005.asmx is used for executing reports. This service is detailed here: http://msdn.microsoft.com/en-us/library/reportexecution2005.reportexecutionservice.aspx The fifth service, ReportServiceAuthentication is used for authentication, but not in the context of this post.
I've wrapped some of the interaction with this service and the printing sub-system up in a few of my own classes. The first is a printing service, which will take the printer name and a renderer object as it's parameters, and deal with the actual printing:
public class PrintingService
{
private IReportRenderer reportRenderer;
private int currentPrintingPage;
private int lastPrintingPage;
private RenderedReport renderedReport;
public void Print(bool isLandscape, string printerName, IReportRenderer renderer)
{
reportRenderer = renderer;
lock (reportRenderer)
{
renderedReport = renderer.RenderReport();
PrintDocument printDocument = new PrintDocument();
printDocument.DefaultPageSettings.Landscape = isLandscape;
printDocument.PrinterSettings.MaximumPage = renderedReport.PageCount;
printDocument.PrinterSettings.MinimumPage = 1;
printDocument.PrinterSettings.PrintRange = PrintRange.SomePages;
printDocument.PrinterSettings.FromPage = 1;
printDocument.PrinterSettings.ToPage = renderedReport.PageCount;
printDocument.PrinterSettings.ToPage = renderedReport.PageCount;
printDocument.PrinterSettings.PrinterName = printerName;
currentPrintingPage = 1;
lastPrintingPage = renderedReport.PageCount;
printDocument.PrintPage += PrintDocumentOutputRequired;
printDocument.Print();
}
}
private void PrintDocumentOutputRequired(object sender, PrintPageEventArgs ev)
{
ev.HasMorePages = false;
if (currentPrintingPage <= lastPrintingPage)
{
reportRenderer.DrawPage(ev.Graphics, currentPrintingPage, renderedReport);
if (++currentPrintingPage <= lastPrintingPage)
{
ev.HasMorePages = true;
}
}
}
}
public class RenderedReport
{
public byte[][] Pages { get; set; }
public int PageCount { get; set; }
public RenderedReport(int numberOfPages, byte[][] pages)
{
PageCount = numberOfPages;
Pages = pages;
}
}
The locks should ensure thread safety for these classes, but I haven't confirmed it yet.
You can use the following code to print the names of all the installed printers:
public void ShowAllInstalledPrinters()
{
PrinterSettings.InstalledPrinters.Cast<string>().ToList<string>().ForEach(Console.WriteLine);
}
The second is the rendering class, which will make the actual call to the service. This is the actual meat of the exercise.
public class ReportRenderer : IReportRenderer
{
private Metafile metafile;
private readonly string reportPath;
private readonly ParameterValue[] parameters;
private readonly string parameterLanguage;
private readonly NetworkCredential serviceCredentials;
private readonly DataSourceCredentials[] dataSourceCredentials;
public ReportRenderer(string reportPath, string parameterLanguage, NetworkCredential serviceCredentials, ParameterValue[] parameters = null, DataSourceCredentials[] dataSourceCredentials = null)
{
Argument.CheckIfNull(parameterLanguage, "parameterLanguage");
Argument.CheckIfNull(reportPath, "reportPath");
Argument.CheckIfNull(serviceCredentials, "serviceCredentials");
this.reportPath = reportPath;
this.parameters = parameters;
this.parameterLanguage = parameterLanguage;
this.serviceCredentials = serviceCredentials;
this.dataSourceCredentials = dataSourceCredentials;
}
public RenderedReport RenderReport()
{
ReportExecutionServiceSoapClient reportingService = new ReportExecutionServiceSoapClient();
reportingService.ClientCredentials.Windows.ClientCredential = serviceCredentials;
reportingService.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
TrustedUserHeader trustedUserHeader = new TrustedUserHeader();
ExecutionInfo2 executionInfo;
ServerInfoHeader serverInfoHeader;
ExecutionHeader executionHeader = reportingService.LoadReport2(trustedUserHeader, reportPath, null, out serverInfoHeader, out executionInfo);
if (parameters != null && parameters.Length != 0)
{
reportingService.SetExecutionParameters2(executionHeader, trustedUserHeader, parameters, parameterLanguage, out executionInfo);
executionHeader.ExecutionID = executionInfo.ExecutionID;
}
if (dataSourceCredentials != null && dataSourceCredentials.Length != 0)
{
reportingService.SetExecutionCredentials2(executionHeader, trustedUserHeader, dataSourceCredentials, out executionInfo);
executionHeader.ExecutionID = executionInfo.ExecutionID;
}
List<byte[]> pages = new List<byte[]>();
int pageIndex = 1;
const string format = "IMAGE";
Byte[] tempPage;
while (true)
{
string deviceInfo = String.Format(@"<DeviceInfo><StartPage>{0}</StartPage><OutputFormat>EMF</OutputFormat></DeviceInfo>",
pageIndex++);
string encoding;
string extension;
string mimeType;
Warning[] warnings;
string[] streamIDs;
reportingService.Render(executionHeader, trustedUserHeader, format, deviceInfo, out tempPage,
out extension, out mimeType, out encoding, out warnings, out streamIDs);
if (tempPage.Length > 0)
{
pages.Add(tempPage);
}
else
{
break;
}
}
return new RenderedReport(pages.Count, pages.ToArray());
}
public void DrawPage(Graphics graphics, int currentPrintingPage, RenderedReport renderedReport)
{
if (renderedReport.Pages[currentPrintingPage - 1] == null)
{
return;
}
MemoryStream currentPageStream = new MemoryStream(renderedReport.Pages[currentPrintingPage - 1])
{
Position = 0
};
if (metafile != null)
{
metafile.Dispose();
metafile = null;
}
metafile = new Metafile(currentPageStream);
lock (metafile)
{
Graphics.EnumerateMetafileProc enumerateMetafileProc = MetafileCallback;
graphics.EnumerateMetafile(metafile, graphics.VisibleClipBounds, enumerateMetafileProc);
enumerateMetafileProc = null;
}
}
private bool MetafileCallback(EmfPlusRecordType recordType, int flags, int dataSize, IntPtr data, PlayRecordCallback callbackData)
{
byte[] dataArray = null;
// Dance around unmanaged code.
if (data != IntPtr.Zero)
{
// Copy the unmanaged record to a managed byte buffer
// that can be used by PlayRecord.
dataArray = new byte[dataSize];
Marshal.Copy(data, dataArray, 0, dataSize);
}
// play the record.
metafile.PlayRecord(recordType, flags, dataSize, dataArray);
return true;
}
}
The datasource credentials passed into the SetExecutionCredentials method is a userid and password associated with CRM. To find these credentials, have a look at the FilteredSystemUser table in your CRM database. Select a suitable, preferably service, user and use the systemuserid field for the username, and the organizationid field for the password. To find the datasource name, open the report you'd like to print, and have a look at the name for the datasource in there. The datasource name is not the name of the actual datasource the report is bound to, but rather the name of the datasource binding in your report. The credentials only apply if you have a datasource explicitly defined in the RDL. If it is only assigned through the report properties outside the report, they're not required.
The Network credentials assigned to your client is the windows credentials of the service. These can be instantiated with values in config, or you can use System.Net.CredentialCache.DefaultCredentials to use the identity of the process you're running as. It is important to enable impersonation. Also note that restrictions may apply if your process is already impersonating a user.
The parameters in the SetExecutionParameters method will be the parameters defined in your report. You only need to specify Name and Value, not Label.
The funniness at the end of the class is to draw the page, and transfer data from unmanaged data structures to managed data structures.
I've also had to make one or two changes to the endpoint's definition in the app.config, to set the authentication up to use NTLM, as seen in the following xml in the app.config.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ReportExecutionServiceSoap" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://192.168.10.57:80/ReportServer/ReportExecution2005.asmx"
binding="basicHttpBinding" bindingConfiguration="ReportExecutionServiceSoap"
contract="ReportExecutionService.ReportExecutionServiceSoap"
name="ReportExecutionServiceSoap" />
</client>
</system.serviceModel>
I've written a small test that will call the print method and print a report:
public void PrintAReport()
{
string printername = @"Microsoft XPS Document Writer";
string reportPath = @"/NZBUpgradeBeta1_MSCRM/CustomReports/{8b7f0cb2-0afa-e011-b6d0-00155d087d2e}";
ParameterValue[] parameters = new ParameterValue[]{};
string parameterLanguage = "en-NZ";
string username = "2FB4FC6A-97CE-E011-833E-00155D087D2E";
string password = "62CF13D1-61C1-E011-B6CB-00155D087D2E";
string datasourcename = @"DataSource1";
NetworkCredential serviceCredentials = new NetworkCredential("intergen.dev","Password1","dev");
ReportRenderer reportRenderer = new ReportRenderer(reportPath, parameters, parameterLanguage, username, password, datasourcename, serviceCredentials);
PrintingService service = new PrintingService();
service.Print(false, printername, reportRenderer);
}
Tuesday, September 20, 2011
Beware the smart quotes when writing code outside a code editor!
Eventually, after much pain and suffering, I typed a single quote next to the existing one in notepad to try escaping some text, and noticed a subtle difference between the quotes. See if you can spot it: ‘ ’ ' While these three characters look similar to you and me, they are in fact very different to text parsers.
My guess is that at some point it must have been inserted by the auto correct feature of a helpful Microsoft Office application. A little further digging exposed that there is a way to turn off the "insert smart quotes" feature in Office applications, explained here.
There are more info available about smart quotes here. A particularly handy tip, is that you can undo the smart quote conversion by pressing ctrl-z immediately after typing the quote character.
Sunday, September 18, 2011
How to Render a partial view in the controller.
My solution is to apply a bit of dependency injection by injecting a new class called a PartialViewRenderer as an interface into my controller. This class will abstract the rendering away, thereby removing the dependency on the view engines etc. from the controller. My controller now becomes easily testable again! This also adheres to the default approach of rendering views etc outside of the controller. You can also test the rendering seperately, but I haven't bothered with that.
The code for the renderer is as follows:
public class PartialViewRenderer : IPartialViewRenderer
{
public string RenderOutput(ControllerContext controllerContext, object model, string partialViewName)
{
using (StringWriter writer = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName);
ViewContext viewContext = new ViewContext(controllerContext, viewResult.View, new ViewDataDictionary(model),
controllerContext.Controller.TempData, writer);
viewResult.View.Render(viewContext, writer);
return writer.GetStringBuilder().ToString();
}
}
}
It is used in the following action:
public JsonResult LoadUrl(string request)
{
RestUrlRequest data = new JavaScriptSerializer().Deserialize(request);
RestSampleUrlModel model = restExamplesProvider.LoadUrl(data);
model.OutputHtml = outputRenderer.RenderOutput(ControllerContext, model, formatToOuputViewMap[data.Format]);
return Json(model, JsonRequestBehavior.AllowGet);
}
outputRenderer is an instance of the PartialViewRenderer that we've injected in this controllers' constructor.A test can be done as such:
[TestMethod]
public void LoadUrlReturnsUrlResultWithOuputFromRendererForFormat()
{
RestSampleUrlModel model = new RestSampleUrlModelFixture().Build();
IRestExamplesProvider samplesProvider = new RestExamplesProviderMockFixture { RestSampleUrlModel = model }.Build();
RestBrowserControllerFixture controllerFixture = new RestBrowserControllerFixture { RestSamplesProvider = samplesProvider };
RestBrowserController controller = controllerFixture.Build();
RestUrlRequest request = new RestUrlRequestFixture { Format = "atom" }.Build();
JsonResult result = controller.LoadUrl(new JavaScriptSerializer().Serialize(request));
result.Should().NotBeNull();
RestSampleUrlModel data = (RestSampleUrlModel) result.Data;
data.OutputHtml.Should().Be("mock render output");
controllerFixture.RestOutputRenderer.AssertWasCalled(mock => mock.RenderOutput(controller.ControllerContext, model, "atom"));
}
I used a mock for the implementation of the OutputRenderer in this test. The mock itself is setup in a seperate fixture class. The renderer class itself can be extended to be more flexible with different overloads for the method, but that is surplus to my requirements.
Thursday, July 7, 2011
Fun with CRM RetrieveMultiple, ConditionOperator.Contains and sql indexing
I had the following code:
QueryExpression query = new QueryExpression("fpis_jobsite")
{
ColumnSet = new ColumnSet { AllColumns = true }
};
query.Criteria = new FilterExpression();
query.Criteria.AddCondition("fpis_name", ConditionOperator.Contains, siteName);
EntityCollection entities = organizationService.RetrieveMultiple(query);
return entities.Entities.Select(BuildJobSite).ToList();
Running it in a test gave me a Generic SQL Error.
After much fuss, I followed the instructions
here to run a SQL trace.
I found the following error:
"Cannot use a CONTAINS or FREETEXT predicate on table or indexed view 'fpis_JobSite' because it is not full-text indexed."
Once I changed the ConditionOperator.Contains operator in my condition to ConditionOperator.Like, the call executed without any further problems.
On a side note, it is not possible to populate child entities by calling RetrieveMultiple with a QueryExpression. You have to make seperate web service calls. In most cases though, you'd be able to craft your QueryExpression to retrieve all the child entities in a single call.
Wednesday, November 17, 2010
Using a filtered index for a unique constraint
I needed to apply a unique constraint on a combination of columns, but only for rows that had not been marked as deleted. After scouring the web, I came to the conclusion that there were two worthwhile ways to achive this.
- Set up a view that only exposes the rows on which the constraint should act. This needs to be a persisted view.
- Instead of a constraint, set up a filtered index.
Discussions on Stack Overflow also suggested using triggers to do some magic in the system, but I have a longstanding hatred for triggers and cursors. One could also opt to enforce your uniqueness constraint in all your inserting and updating stored predures, but this is tiresome and error prone.
I opted to do the filtered index, as that seems to be the cleanest way of achieving my goal. Note that filtered indices are only available on SQL 2008. If you have 2005, you'll need to use a different mechanism, like the constraint on the view.
You can find a comparison of unique indices and unique constraints here http://msdn.microsoft.com/en-us/library/aa224827(SQL.80).aspx The writer comes to the conclusion that they're pretty much the same, with the index having a few more creation options.
Sample Code
This is the table we will use to illustrate the effect of the index:
CREATE TABLE dbo.SerialisedStock (SerialisedStockId INT IDENTITY(1,1) NOT NULL,
StockId INT NOT NULL,
StockCode VARCHAR(50) NOT NULL,
IsDeleted BIT NOT NULL
CONSTRAINT PK_SerialisedStock PRIMARY KEY CLUSTERED
(
SerialisedStockId
)
The code to create our index on the table:
CREATE UNIQUE INDEX UK_SerialisedStock_StockNumber ON SerialisedStock(StockId, StockCode ) WHERE IsDeleted = 0This insert statement will fail if done more than once:
INSERT INTO SerialisedStock(StockId, StockCode, IsDeleted)
VALUES(1, 'aa',0)
This insert statement can be done multiple times:
INSERT INTO SerialisedStock(StockId, StockCode, IsDeleted)
VALUES(1, 'aa',1)
Thursday, October 14, 2010
Cool Visual Studio 2010 Extensions
- giving you a shortcut to reopen recently closed documents (and an optional windows displaying a list of recently closed documents).
- adds a command on the context menu of the solution explorer that will open up a command prompt with the working directory set to the path of the item you clicked on.
- Adds a command to open the containing folder of an item clicked on in the solution explorer.
- copy and paste references.
- email a code snippet.
http://visualstudiogallery.msdn.microsoft.com/en-us/e5f41ad9-4edc-4912-bca3-91147db95b99
For those of us used to scroll in any direction by dragging with the middle mouse button in almost any Microsoft product, this AutoScroll extension will re-add that functionality to Visual Studio 2010. (This is not an invitation for a debate on class sizes!)
http://vs2010autoscroller.codeplex.com/
There are a couple of other add-ons and extensions that I also use (and won't go without) such as Resharper, Ankh (for svn), TestDriven.Net (though Resharper can do the same stuff) and GhostDoc.
Thursday, March 25, 2010
A tribute to Joel
Joel's writing has been a great inspiration to me, and have stimulated many fiery connerdsations at the pub. I still browse back to some of the articles in his archive from time to time. They have the type of content that makes them remain relevant, in the same way as Peopleware remains relevant, many years after being written.
Cheers Joel, and good luck for the future!
Tuesday, February 16, 2010
Tips and tricks for writing Windows services in C#
- If you haven’t done this before, or forgot everything you’ve learned, here’s a tutorial: http://www.grinn.net/blog/dev/2008/01/windows-services-in-c-part-1.html or refer to http://msdn.microsoft.com/en-us/library/zt39148a(VS.80).aspx
- Put your Business Logic/BOL/code that does something in a separate assembly, or at the very least in a separate method marked public, so that you can add a gui/console application/unit test to your solution to execute this code. It saves a lot of time in debugging code.
- The default timer in the toolbox, System.Windows.Forms.Timer, does not work in a service. You need to use System.Timers.Timer, which can be added to the toolbox. Refer here for an explanation of why it doesn’t work (Winforms timers need a messagepump on a UI thread): http://msdn.microsoft.com/en-us/library/tb9yt5e6.aspx
- Remember to stop your timer while processing, and restart it afterwards.To add an installer, right click on the component view of your service, and click “Add Installer”. Don’t bother with manually adding an installer to your project.
- Add a setup project to your solution to install the service. Add the service’s primary output action to the install, rollback and uninstall actions. If you don’t add it to rollback, a failure after the base.Install(stateSaver) in the installer class of the service, will leave you with a service that is installed, but can’t be replaced or uninstalled by your MSI. When that happens you need to use the InstallUtil command from the command line.
- To use the installutil from the command line, type "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installutil"
where is the name of the assembly of your service to install the service. Add the /u flag to uninstall the service. - Use Debug.Assert(false, "Attach here to debug") to have your service pop up a message to which you can attach the debugger to step through your code. Not absolutely neccesary, but it makes things easier. For that matter, this can also be used when debugging installers, or anything else requiring to be paused at a certain place for attachment, before a breakpoint can be hit.
- Remember to log exceptions, they will not be logged automatically (maybe if you use the logging enterprise application block?). The eventlog is a good place to do this, but remember to register your source first. This is probably best done in the installer, unless you make it configurable in the service. Creating a source requires admin privileges. Here’s a how-to: http://msdn.microsoft.com/en-us/library/k00ce235.aspx
- Include something to stop your service after n number of concurrent failures, or to stop logging the exceptions. You don't want to fill up the eventlog with nonsense.
- Application settings in the config file is used as usual with Properties.Settings.Default.PropertyName
- The default service name can be set on the properties of the service in the component view. There are a few other useful properties here, like CanPauseAndContinue. Check it out.
- The account for which to run this service is set in the properties of the ProcessInstaller component in the ProjectInstaller file’s component view.
Sunday, November 8, 2009
A view of the modern Business Analyst
This then leads us to the question: What is a good BA? It’s a very difficult thing to quantify, because quite often, we don’t really understand what we expect from our BA.
Our organisation used to expect them to thoroughly and meticulously detail the requirements for any new development. For months they would sit down with customers, and draw up pages and pages of lists of things the software should and shouldn’t do. Really keen BA’s also included diagrams depicting data and process flows. They would do all kinds of modelling to exactly indicate every eventuality. The reams of documents would then be signed off, and sent to the development teams. The BA’s would then move on to analyse another part of the business by creating a new set of requirements for another piece of software.
As far as the software products go, it didn’t work very well. The developers were invariable left with such vast and daunting tasks, that they just seem to ignore all the specs, and wrote a piece of software that they thought would work for the users. Sometimes they sought some input from the users. On rare occasions they even got it, and those were the more likely projects to succeed in providing some semblance of success. One of my colleagues remarked that in the 3 years here, he has never worked on a project that went live.
Our partial solution to the problem is agile development. This seems to be working very well for many software development groups (think Microsoft, Google and others). Without going into a discussion of agile (there’s plenty of them around), following it left an interesting dilemma. What to do with our BA’s? You see, traditionally, we expected them to fit in between the users and developers. Other, more advanced organisations, expected them to stand between anyone of a technical inclination and the users. In university, we were taught that the expectation of the business analyst was to represent the combined knowledge of the business unit in documentation so it may be encapsulate in software systems.
With the agile approach, we chucked a lot of that out the window. We invited the users to the party. We started interacting directly with the first tier owners and manufacturers of business knowledge. We changed our waterfall model which had everyone only partaking in a stage of the development. Under the new agile approach, everyone is a part of the entire lifespan of the project. The success and failure is a shared burden of the entire team, all the time. If the product get to UAT, and isn’t what the users wanted, everyone is to blame.
The good BA’s developed a new position in the process. They moved from being the guardians of the business knowledge to gentle facilitators. Instead of being a link in a game of Chinese Whispers, they set up telephone conferences. They stopped planning systems that would hide the processing difficulties, and started helping users to better understand their processes. They became less involved in the technology, and more involved with the problem. Together, we are changing the old pattern of creating expensive systems that perform inefficient tasks. We are making change where it’s cheapest, and most effective.
So where do we stand with our expectations from Business Analysts? What is the distilled essence of their function? In my opinion, the modern BA has one imperative: Empower the business to collaborate effectively in the creation of fit for purpose software.
When a BA strives to attain this goal, it makes life easier for me, as a developer. When I ask our user representatives whether they would mind if we cut the print function down to only print the component you’re looking at, they can actually debate the merits of either approach! In the old days, there would be no option, leaving you to implement the function as it was specified. You would have to create the page that allowed the user to print all 50 pages of tables and graphs, and would never be used because it took too long to load. Now, the specification is updated (by changing the acceptance criteria on the user story in the product backlog) and we can devote our effort to things that the users really care about, like improving navigation between the different tables and graphs. With empowered users, we can focus our resources to where it matters most for them. With BA’s focusing on the problem rather than the solution, many more possible solutions can be generated. Solutions can now involve changing the way users work, rather than the system they use. Our products are now going live, and the users are satisfied.
Thursday, November 5, 2009
How to enable tracing on WCF services to troubleshoot things like serialization errors
It will help you debug that annoying "The connection has been forcibly closed" error, that has no usefull information attached to it at all.
1. Add the following code in your web.config or app.config for the WCF service:
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="All"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "c:\log\Traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
This code should be added after the
<configSections>
element. Not doing so will cause an error.
Alternatively, use the configuration editor at Start -> All Programs -> Microsoft Windows SDK v6.0A -> Tools -> Service Configuration Editor to enable the diagnostics.
2. Make sure the "c:\log\" path is created and accessible to the appropriate accounts (I've just given the "everyone" account write access to it, but the .net worker process account would probably be enough)
3. Open the Traces.svclog file with the service traceviewer, which can be found here:
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe"
or go to Start -> All Programs -> Microsoft Windows SDK v6.0A -> Tools -> Service Trace Viewer
And that's it. The service viewer will show you any errors that was logged, and provides a very handy way to drill into the details.