Wednesday, June 23, 2010

Mocking Web Service For Silverlight Consumption

One of my colleague ran into this typical dependency chain. The requirement was to show data in a Silverlight 3.0 data grid. Picture below summarizes the dependency chain. This picture is the very reason why we have IOC frameworks and how they make life easy. I mean, why should my Datagrid care about the fact that Synch framework is doing its job properly or not.

Dependency

 

 

 

 

 

 

 

 

 

 

 

You can imagine how much time it would take for the developer working on the datagrid to resolve all the preceding 8 dependencies just to bind to the grid. Welcome to IOC (for those of you going “oh not again” please read on, there is little twist, at least it was for me).

Ideally we should only be concerned about our ViewModel and nothing else. Since ViewModel is using a WCF Proxy we already have an interface that we can mock. And here lies the key:

Mock the web service interface and inject it using the UnityBootstrapper

If you have basic Prism project injection should be straight forward. This is what we did in our bootstrapper:

this.Container.RegisterType<IMyService, MyServiceMock>();
myModel = IMyService.GetData();


Everything was smooth until this point in refactoring. Than I ran into trouble with actual mock implementation of the interface serialized in WCF proxy. Since all the methods get serialized into their corresponding Begin and End versions and the fact that everything in Silverlight 3.0 framework requires you to make asynchronous calls, you cannot just create straight interface mock and start binding.



Basically you have to be aware that you are mocking the asynchronous version of the interface and should not attempt to capture the underlying channel details in the mock. Given below is the code and new (much shorter and required) dependency chain I ended up with:




public class MyServiceMock : IMyService
{
public MyServiceMock()
{ }

#region IMyServiceMembers

public IAsyncResult BeginMyMethod(AsyncCallback callback, object asyncState)
{
callback.Invoke(null); // <—Trick your caller and tell them async operation complete right away
return null;
}

public ObservableCollection<MyClass> EndMyMethod(IAsyncResult result)
{
ObservableCollection<MyClass> mockedList = new ObservableCollection<MyClass>();
mockedList.Add(new MyClass());
return mockedList;
}


Technorati Tags: ,,,


    #endregion
}


*I am assuming no mocking framework is being used but the notion will still translate.



Here is the new dependency chain for testing my UI.



ShortDependency 
Short, Sweet and Testable.

Sunday, June 08, 2008

Entity framework and OpenFileDialog

Bugs manifest themselve in a strangest possible ways. Here is one of those...

1. Created a Winform App
2. One one of the forms in my app invoked window's OpenFileDialog
3. After closing the OpenFileDialog (not cancelling), any call to create new ObjectContext fails with following error:

The specified metadata path is not valid. A valid path must be either an existing directory, an existing file with extension '.csdl', '.ssdl', or '.msl', or a URI that identifies an embedded resource.

Strange right ? How on earth can OpenFileDialog affect the creation of ObjectContext ?
After some close inspection and frustration, it turns out that the error message is actually pointitng to a correct cause:

The specified metadata path is not valid


Reason and Solution:

1. I have not decompiled or looked at the Entity framework code but at this point I am certian that the default constructor (the one which look at the connection string) of ObjectContext is trying to load the metadata from Environment.CurrentDirectory.
2. When application is started the Environment.CurrentDirectory = Application.StartupPath, therefore everything is happy and functional.
3. After closing the OpenFileDialog the Environment.CurrentDirectory property changes to wherever the dialog was pointing to.
4. But the connectionstring in appconfig is still point to "./*" which is transalting to Environment.CurrentDirectory, thus causing the load error.

Solution:

Either change the autogenerated connection string to point to an absolute path.
Or
Anytime you change the Environment.CurrentDirectory property, remember to change it back to Environment.CurrentDirectory = Application.StartupPath
Or
Wait for the next release, hoping that the bug will be fixed after somebody reads this post ;-)

If this post does not help you then there is another onehere which explains the solution for the same error message but under totally different and unrelated circumstances.

Friday, May 18, 2007

Switching View in Infopath form from WebForm host

Infopath browser enabled forms offer a lot of flexibility and productivity. But with all the moving pieces involved in development and deployment of:

"Browser enabled - administrative approved - full trust - deployed to Sharepoint as feature-hosted in a web part" forms,

encoutering some simple glitches can cause some trouble. A solution to one of these small thing is posted here...

The scenario: You have a form with multiple view but want to invoke switch view from an ASPX hosting enviroment..

Solution:
1. Enable toolbars in your form (Tools-> Form Options -> Browser-> ShowToolbars)
2. Deploy it to a site collection and enable Web Page viewing from advance option in Form Template Library
3. Create a hosting environ. Use XML Form View control in your Web part or on your ASPX running under Form Services context.
4. Set the XsnLocation on the FormViewer control and open in browser.
5. View html source of the generated web page and you will find
"Toolbar.HandleViewSwitching(this)" being called on on change of a dropdown.
6. That's it !!! now go back disable the tollbars from your form and redeploy.
7. This time the drop down will not be rendered, hence no code to switch views.
8. Implement some code to spit out a drop down to you html. (You can do that in render method of you web part or pre render of your page, what ever makes more sense in your implementation)
9. Now istead of calling "Toolbar.HandleViewSwitching(this)" with this just pass in a reference to your drop down !!!

Here is a sample code:


<script type="text/javascript">
function ChangeView(viewName)
{
var dd = document.getElementById("FakeDropdown");
dd.value=viewName;
Toolbar.HandleViewDropdown(dd);
}
</script>
</span>
<select id="FakeDropdown" style="DISPLAY: none"> <option value="'View">View1</option> <option value="'View2'">View2</option></select>

<div onclick="ChangeView('View2')">Click Me</div>

This instructs the in memory from viewer script to think that view change is requested.