Monday, 5 December 2011

Mocking out Environment.Exit

Question I came across recently on Twitter.

"How do I write a test when there's an Environment.Exit?! :("

Very good question... My answer was basically rewrite the code! A really quick way to do this is create a static action that will allow you to mock it out. What if I created a class called MyEnvironment with this Action:


public class MyEnvironment
{
public static Action Exit = exitCode => Environment.Exit(exitCode);
}


In code I can just replace the call with this:


MyEnvironment.Exit(0);


And now, in my testing I can do something like this:


MyEnvironment.Exit = exitCode => { };


Voila! No more interrupted tests :)

Thursday, 24 November 2011

Dynamics CRM 2011 - unable to unregister plugin

There seems to be a bug in CRM 2011 if you make changes to a DLL or remove a DLL from the server/bin/assembly folder and subsequently try to unregister the associated plugin. For some reason (I have yet to figure out) 2011 needs to load that plugin assembly again before it can unregister it. Obviously it runs into problems trying to reload this plugin and throws an error. My best guess as to why it needs to do this is it has to unregister the SDKMessageProcessingSteps in the background and I bet that as soon as it attempts to access these items it attempts to load up the assembly. So we end up with a catch 22 situation.

Here's a way to see this in action:

1. Create a basic plugin called something like "TestPlugin"

2. Copy the plugin dll to the server/bin/assembly folder

3. Register this plugin using the "Disk" option using the PluginRegistrationTool

4. Test the plugin (so that it is loaded and activated)

5. Go back to the code and change the plugin name to something like "TestPluginNameChange"

6. Copy the DLLs over again (If you get an access error on the files perform an IISReset)

7. Try to unregister the plugin...

You end up getting an error something like this:


<ErrorCode>-2147220970</ErrorCode>
<ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<Message>System.Web.HttpUnhandledException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #A28C2B17</Message>


So what's the solution? There's a few options here.

1. Copy back in the old DLLs... I don't usually have the original DLLs so that's out (I'm usually in developer mode when this happens and quickly recycling DLLs).

2. If it's an easy edit try to revert your code back and copy in these DLLs. Attempt to unregister.

3. If this doesn't work try to update the assembly with the new DLLs (that were edited as close back to the originals as possible). Then unregister.

4. If this still fails try to update the assembly again but this time switch over from Disk to Database. Then unregister.

5. If you're reading this step you've managed to create a situation I once ran into as well... and couldn't resolve... watch this space for a solution!


All in all, be careful with plugins during development. When replacing a plugin that you've edited quite a lot try get into a habit of unloading the existing assemblies before you load up the new ones. Just takes one slip and you land yourself in a bit of a mess.

Tuesday, 25 October 2011

Silverlight, JSON and dynamic types...

Todays Dynamics 2011 task was to investigate using JSON within a Silverlight control. I started this task with high levels of excitement being new to the whole restful/JSON scene. Yes, I know, I am a bit of a late-comer here! The purpose of this task was to create a generic control I could put on a Dynamics CRM Form. This control was going to be driven by data from an external restful service. I don't want to have to reconfigure this control every time my data changes, so the purpose is to drive the label and value from this external source. So, this isn't about communicating with a Dynamics database using OData/JSON.

A quick google on how I do this results in me writing the following snippet:


var proxy = new WebClient();
proxy.OpenReadCompleted += proxy_OpenReadCompleted;
proxy.OpenReadAsync(new Uri("restfulurl"));

// Calling the following method...
private void proxy_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
var strm = new StreamReader(e.Result);
string jsonText = strm.ReadToEnd();
// ... etc
}



This is where I hit my first road block: Cross site scripting. I spent quite a while on that, and still haven't figured out what I'm going to do, so I'm going to save that for another post. Plus, this really boils down to a Dynamics 2011 cloud issue, so let's move on. If you're not doing this via Dynamics 2011 then you should be able to do the above in a standard Silverlight control. For now I shall spoof the JSON by hardcoding the string...

Next, how do we parse this into a dynamic type? In C# 4.0 we can do some really nice stuff like this:


using System.Web.Script.Serialization;

...

JavaScriptSerializer jss = new JavaScriptSerializer();
var d = jss.Deserialize(jsonText);



Roadblock 2... JavaScriptSerializer was depreciated after Silverlight 1.1... HRMPH!

Silverlight, sometimes I hate you...

After countless searches and getting very close to embarking on a journey to build a JSON parser... I'm going to give a call out to a great blog post by jprichardson here. Saved me a few days effort, cheers mate! I quickly grabbed this source from GIT, built it, and stuck the silverlight libraries into my project. Now I do this:


var jsp = new JsonParser();
dynamic json = jsp.Parse(jsonText);




Whazzam, I have dynamic object from my JSON!

I have to say though, the deeper I dig into Silverlight the more shocked I am at the little things that take so much effort...

Tuesday, 27 September 2011

How to post code in blogger... part deux!

Ok, after struggling initially with posting code in blogger (posting html code in blogger) I managed to figure out a much better way to do this. At the time of posting the above I didn't realise the following tags existed:


<pre name="code">
code goes here!
</pre>


This is much better and results in better formatted posts. The only real "gotcha" is you'll have to replace some "html" style tags with their html safe equivalent. For example, "<" becomes "&lt;"

Now to go back and fix my blog...

Monday, 19 September 2011

MS Dynamics 2011 and MVVM

So, I've been out of the Microsoft Dynamics world for about a year now (and semi AWOL in the process!), but after changing jobs I find myself back in this world using 2011. First up, Silverlight! Now, I have have started to notice quite a bit that a lot of samples or guides on CRM 2011 and Silverlight don't seem to use MVVM. Why on earth is that? First things first, this in my opinion sheds a very bad light on Dynamics development. The very first project I get to work on had already been started by a previous developer. I open up the project and to my dismay I see absolutely zero view models. Task 1 - Push TDD.

So, why would we not use MVVM in Dynamics 2011? Let's walk through a sample I found and my phase 1 of refactoring. I open up the code behind and find this:


private DataItemCollection _collection;
public System.String _serverUrl;
private string _userId;
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
GetPageInformation();
LoadCompanies();
}

private void LoadCompanies()
{
_collection = new DataItemCollection();
QueryExpression query = QueriesHelper.GetAllAccounts();
SoapHelper.BeginExecuteRetrieveMultiple(query, new AsyncCallback(GetAccountsCompleted), null);
}

private void GetAccountsCompleted(IAsyncResult result)
{
OrganizationResponse response = ((IOrganizationService)result.AsyncState).EndExecute(result);
if ((response != null) && (response.Results.Count > 0))
{

...I SHALL PROTECT YOUR EYES FROM A MONSTROSITY OF A FUNCTION HERE...

}

if (!Deployment.Current.Dispatcher.CheckAccess())
{
Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
this.TreeViewClients.DataContext = _collection;
});
}
else
{
this.TreeViewClients.DataContext = _collection;
}
}

private void GetPageInformation()
{
ScriptObject xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
ScriptObject page = (ScriptObject)xrm.GetProperty("Page");
ScriptObject pageContext = (ScriptObject)page.GetProperty("context");
_userId = (string)pageContext.Invoke("getUserId");
_serverUrl = (string)pageContext.Invoke("getServerUrl");
}


So what do we have here? What hints do I get as to why we wouldn't implement MVVM? Ok, so it looks like either the developer hadn't done much Silverlight/WPF before... or didn't quite know how to MVVM this. Looking at the code I can see that there's 2 things that we need to be considerate of when considering MVVM:

1. Queries need to run Asynchronous.

2. Access to our dispatcher for when we need to run "stuff" on the UI thread.

So how do we move this across to a MVVM structure then? Step 1, let's create a ViewModel:


public class MyDamnViewModel
{
private readonly Dispatcher _dispatcher;

public TeamCalendarViewModel()
{
_dispatcher = Deployment.Current.Dispatcher;
}
}


One plan here will be to allow for testing, but for now just copy the dispatcher to a local variable.

So what else can we add to this? How about everything! Considering the old form set everything up in the "onload" let's go with this for now. Let's just copy ALL methods across to my viewmodel and add the 2 method calls to our ViewModel constructor (GetPageInformation and LoadCompanies)... This will cause 1 major problem...


this.TreeViewClients.DataContext = _collection;


What do we do? I notice my DataItemCollection already inherits from ObservableCollection... let's work with that for now and mark for review... Refactor the variable _collection so that we expose as a public ObservableCollection property:


private DataItemCollection _collection;
public ObservableCollection<DataItem> NowWeHaveACollection
{
get { return _collection; }
set
{
_collection= (DataItemCollection)value;
NotifyPropertyChanged("NowWeHaveACollection");
}
}


I won't go into NotifyPropertyChanged stuff into too much depth here... but to get us by I just inherited from INotifyPropertyChanged and added this code to the view model:


public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}


Let's worry about refactoring and tidying all that up in a phase 2. For now I just want to get a basic MVVM structure in place.

So what did this new property give us? We can just set the property instead of directly accessing the control:


NowWeHaveACollection = _collection;


Nearly there yet boss? Not quite. Code should be there, but we don't have anything hooked up. Let's set up our datacontext in the XAML:


<usercontrol.datacontext>
<MyDamnViewModel />
</usercontrol.datacontext>


And set our bindings up in the XAML instead of in the code. In my case it was a telerik tree view so we have converters and all sorts of rubbish in the code... I'll save that for another post. Let's pretend for now it's a bog standard list or something. Set this on your object in the XAML:


ItemsSource="{Binding NowWeHaveACollection}"


And now our main form looks like this:


public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
}


Ignoring the fact that it's called "MainPage" and some "phase 2" refactoring we're pretty much done.

So, to answer the question - No reason not to use MVVM in Dynamics 2011. I'd like to see less samples using direct code behind please!!