måndag 29 september 2008
Nifty SQL procedure to generate sql export (MSSQL)
This feature is lacking (to my knowledge) from the Import/Export within SQL Management Studio. So after some googling, I found a couple of shareware programs doing it, but I also found a stored procedure doing the same thing - for free.
Here's the link:
http://vyaskn.tripod.com/code/generate_inserts_2005.txt
onsdag 25 juni 2008
Converting generic lists of concrete class to lists of implemented interface
Have you noticed that if you fill a generic List with a concrete class that implements an interface, the generic List does not think it is filled with objects of that interface? And you can't cast the list to a List of the interface.
Let's look at a simple example where we have an IPerson interface and a concrete class, Person, implementing IPerson:
namespace ConvertingGenericLists
{
public interface IPerson
{
string Name { get; set; }
}
public class Person : IPerson
{
public string Name { get; set; }
}
}
Nothing strange. However, if we create a List<Person> it is not a List<IPerson> and the compiler will not tolerate a cast like (List<IPerson>).
However, every element in the list is both of type Person and IPerson, but the list itself is of Person.
The neat trick is to use the ConvertAll()-method in List and with a simple lambda-method convert it.
Like this (PersonList is a List<Person>):
IPersonList = PersonList.ConvertAll(c => (IPerson) c);
Now the lists contents is that of the interface, but as you will see in the code below, every element is still of IPerson and Person.
And here is a complete example using NUnit tests:
using System.Collections.Generic;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
namespace ConvertingGenericLists
{
[TestFixture]
public class Tests
{
private List<Person> PersonList;
private List<IPerson> IPersonList;
[TestFixtureSetUp]
public void Setup()
{
PersonList = new List<Person>
{
new Person {Name = "Aurel"},
new Person {Name = "Thomas"},
new Person {Name = "Lasse"}
};
//And the magic of ConvertAll() and lamdba:
IPersonList = PersonList.ConvertAll(c => (IPerson) c);
}
[Test]
public void PersonList_Is_Of_Base_Type_Only()
{
Assert.That(PersonList, Is.InstanceOfType(typeof(List<Person>)));
Assert.That(PersonList, Is.InstanceOfType(typeof(IList<Person>)));
Assert.That(PersonList, Is.InstanceOfType(typeof(IEnumerable<Person>)));
//An element in PersonList is indeed of type IPerson:
Assert.That(PersonList[0], Is.InstanceOfType(typeof(IPerson)));
//But PersonList is not a list of IPersons!
Assert.That(PersonList, Is.Not.InstanceOfType(typeof(List<IPerson>)));
}
[Test]
public void IPersonList_Is_A_List_Of_IPerson()
{
Assert.That(IPersonList, Is.InstanceOfType(typeof(IList<IPerson>)));
Assert.That(IPersonList, Is.InstanceOfType(typeof(List<IPerson>)));
Assert.That(IPersonList, Is.InstanceOfType(typeof(IEnumerable<IPerson>)));
//IPersonlist is not of the implementing type anymore:
Assert.That(IPersonList, Is.Not.InstanceOfType(typeof(List<Person>)));
Assert.That(IPersonList, Is.Not.InstanceOfType(typeof(IList<Person>)));
Assert.That(IPersonList, Is.Not.InstanceOfType(typeof(IEnumerable<Person>)));
//But an element in IPersonList is STILL a Person and a IPerson!
Assert.That(IPersonList[0], Is.InstanceOfType(typeof(Person)));
Assert.That(IPersonList[0], Is.InstanceOfType(typeof(IPerson)));
}
}
}
fredag 2 maj 2008
Calling WCF from jQuery using parameters
This continues our discoveries in the articles "Returning true JSON from WCF services", "Return JSON from Ajax-enabled WCF Service" and "Using jQuery with JSon-enabled WCF Services".
We will now add two parameters to our DoWork-method and supply them when we call them using jQuery.
Open up the "AjaxEnabled.svc.cs" and add two parameters, string name and int id:
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web;
namespace Alaz.DotNetDiscoveries.JSONWithWCF
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class AjaxEnabled
{
// Add [WebGet] attribute to use HTTP GET
[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Json,BodyStyle = WebMessageBodyStyle.Bare)]
public MyClass DoWork(string name, int id)
{
var returnObject = new MyClass
{
//Use our fresh parameters:
Id = id,
Name = name,
//Added a call to HttpContext.Current:
NoPublicGet = HttpContext.Current.Request.RawUrl,
IHaveNoDataMemberAttribute = "Meaningless",
InternalProperty = 155
};
return returnObject;
}
// Add more operations here and mark them with [OperationContract]
}
}
Then try to run it with the url "AjaxEnabled.svc/DoWork?name=Zlatan&id=8". Your answer should be:
{"Id":8,"InternalProperty":155,"Name":"Zlatan","NoPublicGet":"\/AjaxEnabled.svc\/DoWork?name=Zlatan&id=8"}
Make (or add to our previous example) a web page like this (note that in our example there is no check that the number-field only provides an integer):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Test jQuery, WCF and JSon</title>
<script src="script/jquery-1.2.2.js" type="text/javascript"></script>
<script type="text/javascript">
$().ready(function()
{
$("#myButt").click(function()
{
$.getJSON("TrueJSON.svc/DoWork",function(data)
{
alert("Name=" + data.Name + "\nId=" + data.Id + "\nNoPublicGet="+data.NoPublicGet + "\nInternalProperty=" + data.InternalProperty );
});
});
$("#parameterButt").click(function()
{
var nameValue=$("#name").val();
var idValue=$("#id").val();
$.getJSON("AjaxEnabled.svc/DoWork",{name:nameValue,id:idValue},function(data)
{
alert("Name=" + data.Name + "\nId=" + data.Id + "\nNoPublicGet="+data.NoPublicGet + "\nInternalProperty=" + data.InternalProperty );
});
});
});
</script>
</head>
<body>
<input type="button" value="Get values from server" id="myButt" />
<p>
<input type="text" id="name" value="Zlatan" /><br />
<input type="text" id="id" value="8" /><br />
<input type="button" value="Get values from server, call with parameters" id="parameterButt" />
</p>
</body>
</html>
Nice, isn't it?
That concludes this article-series about using WCF services with jQuery.
Good luck!
Using jQuery with JSon-enabled WCF Services
Download the .js file from http://jquery.com/, make a html or aspx-page and point a script-src-tag to the downloaded script.
Below I have added a simple jQuery-script that gets our example-data from the WCF service and alerts the results.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Test jQuery, WCF and JSon</title>
<script src="script/jquery-1.2.2.js" type="text/javascript"></script>
<script type="text/javascript">
$().ready(function()
{
$("#myButt").click(function()
{
$.getJSON("TrueJSON.svc/DoWork",function(data)
{
alert("Name=" + data.Name + "\nId=" + data.Id + "\nNoPublicGet="+data.NoPublicGet + "\nInternalProperty=" + data.InternalProperty );
});
});
});
</script>
</head>
<body>
<input type="button" value="Get values from server" id="myButt" />
</body>
</html>
Simple, isn't it?
If you are unfamiliar with the jQuery syntax, read more about it on http://jquery.com/.
Ok, lets move on, now we are going to wrap things up and show how we can send in some parameters to our WCF Service in the article "Calling WCF from jQuery using parameters".
Accessing HttpContext.Current from WCF Service
By default, when you create an new WCF Service in a web site, they live side-by-side and the WCF service cannot access the HttpContext.Current-object (and the other ASP.NET-features like File/URL-authorization, HttpModules and ASP.NET impersonation), and in some Ajax-scenarios, we really need it.
There are two simple steps for enabling it.
First, you need to turn it on in the web config, look for "system.serviceModel" and add the "serviceHostingEnvironment"-tag like this:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
Second, add the attribute "[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]" to your service-class (it can't be in the interface):
using System.ServiceModel.Activation;
namespace Alaz.DotNetDiscoveries.JSONWithWCF
{
// NOTE: If you change the class name "TrueJSON" here, you must also update the reference to "TrueJSON" in Web.config.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class TrueJSON : ITrueJSON
{
public MyClass DoWork()
{
var returnObject = new MyClass
{
Id = 1,
IHaveNoDataMemberAttribute = "Meaningless",
Name = "Satchmo",
NoPublicGet = "Hello world!",
InternalProperty = 155
};
return returnObject;
}
}
}
And you are done!
MSDN documentation here.
Return JSON from Ajax-enabled WCF Service
This is another way to return JSON from WCF than I described in the previous article "Returning true JSON from WCF services".
As in that article, this method was discovered using trail-and-error, and some Googling. I have not studied WCF in depth, I just barely learn what I need to, so there may very well be some better way to do it, I just haven't been able to find it yet.
- In a web project, "Add new item.." and choose "Ajax-enabled WCF Service", let's call it "AjaxEnabled.svc"
- This service is made without an interface to specify the methods (i.e. no "IAjaxEnabled.cs" was created as it would have done if you choose to add a new WCF Service like in the previous article), and consists of the single method DoWork().
- Let's create something to return, add the "MyClass" from the other article and replace the method DoWork() from there too.
Add the [WebGet] attribute too, since there doesn't seem to be a $.postJSON-function in jQuery.
You should now have an AjaxEnabled.svc.cs that looks like:
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
namespace Alaz.DotNetDiscoveries.JSONWithWCF
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class AjaxEnabled
{
// Add [WebGet] attribute to use HTTP GET
[OperationContract]
[WebGet]
public MyClass DoWork()
{
var returnObject = new MyClass
{
Id = 1,
IHaveNoDataMemberAttribute = "Meaningless",
Name = "Satchmo",
NoPublicGet = "Hello world!",
InternalProperty = 155
};
return returnObject;
}
// Add more operations here and mark them with [OperationContract]
}
}
- Let's try it out, run the project and call the service with adding /DoWork to the AjaxEnabled.svc-url. You should've got:
<MyClass xmlns="http://schemas.datacontract.org/2004/07/Alaz.DotNetDiscoveries.JSONWithWCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Id>1</Id>
<InternalProperty>155</InternalProperty>
<Name>Satchmo</Name>
<NoPublicGet>Hello world!</NoPublicGet>
</MyClass>
Not really what we've wanted, apparently MS Ajax implementation use xml to communicate. Time to fiddle with some settings then: - Add the ResponseFormat-property to WebGet, and set it to Json (default seems to be xml):
[WebGet(ResponseFormat=WebMessageFormat.Json)]
- Run again, inspect the response in notepad, and now we got some Json, but not really in the format we would like to:
{"d":{"__type":"MyClass:#Alaz.DotNetDiscoveries.JSONWithWCF","Id":1,"InternalProperty":155,"Name":"Satchmo","NoPublicGet":"Hello world!"}}
There seem's to be some envelope around it. Let's remove it: - Set the BodyFormat-property to Bare, we do not wan't to have Wrapped messages, only bare Json:
[WebGet(ResponseFormat=WebMessageFormat.Json,BodyStyle = WebMessageBodyStyle.Bare)]
- Run again, and you will get an error:
Server Error in '/' Application.
--------------------------------------------------------------------------------
The body style 'Bare' is not supported by 'WebScriptEnablingBehavior'. Change the body style to be 'WrappedRequest'. - We must change something in the web.config, look at this tag:
<behavior name="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabledAspNetAjaxBehavior">
<enableWebScript />
</behavior>
- Change "enableWebScript" to "webHttp" like this:
<behavior name="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabledAspNetAjaxBehavior">
<webHttp />
</behavior>
The behavior is connected to:
<service name="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabled">
<endpoint address="" behaviorConfiguration="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabledAspNetAjaxBehavior"
binding="webHttpBinding" contract="Alaz.DotNetDiscoveries.JSONWithWCF.AjaxEnabled" />
</service>
- Run again, and now you got the correct Json-string {"Id":1,"InternalProperty":155,"Name":"Satchmo","NoPublicGet":"Hello world!"}.
- One more thing worth mention is the AspNetCompatibilityRequirements-attribute to the service-class:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
If you want to access the current HttpContext, using ASP.NET's file/url authorization and that normal ASP.NET-stuff you must use either AspNetCompatibilityRequirementsMode.Allowed as in this example, or AspNetCompatibilityRequirementsMode.Required. My advice is to use Required if you need any of the ASP.NET-features, then the service throws an error if it is not enabled. You must enable this in the web.config (however, the "Add new Ajax-enabled WCF service" seems to add it automagically):
If "Allowed" you can run it even if web.config says "false", and you could have a hard time finding out why HttpContext.Current is null.<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
tisdag 29 april 2008
Returning true JSON from WCF services
In a current project I desperately wanted to use jQuery in the frontend for doing some nice Ajax-stuff. I don't really care for Microsoft's implementation of ASP.NET AJAX, I've used it in some earlier projects. Anyway, this time my goal was to use the jQuery $.getJSON - function to pull data from the server.
At first, I just did an aspx-page and did an output with a ToJSON-extension (see Scott Guthrie's blogpost). No sin in that ofc, but not very elegant or practical, especially if you would like to send in some parameters. The elegant solution would be to use WCF services. With some nifty attributes and some additional parameters in web.config, it worked. This method was discovered using trail-and-error, and some Googling. I have not studied WCF in depth, I just barely learn what I need to, so there may very well be some better way to do it, I just haven't been able to find it yet.
This is how I did it using Visual Studio 2008:
- Create an ASP.NET Web Application (would surely work with ASP.NET Web Site too, but I prefer the Web Application)
- Add a new item, a WCF Service (not "Ajax-enabled WCF-service, we'll look at it in the next article), lets call it TrueJSON.
- You now have an WCF-service with .svc as extension, and that service implements an Interface. It's in the interface we'll set the attributes needed to return JSON.
- Create a class, MyClass as below. The attributes "DataContract" and "DataMember" must be defined for the class and the properties that would be returned through the WCF service. As you will see later on, so the WCF service will return everything marked as "DataMember", even if there is a private get.
using System.Runtime.Serialization;
namespace Alaz.DotNetDiscoveries.JSONWithWCF
{
[DataContract]
public class MyClass
{
[DataMember]
public int Id { get; set;}
[DataMember]
public string Name { get; set; }
public string IHaveNoDataMemberAttribute { get; set;}
[DataMember]
public string NoPublicGet { private get; set; }
[DataMember]
internal ushort InternalProperty { get; set; }
}
}
- Now add a reference to System.ServiceModel.Web (this is where the WebGet-attribute is located).
- Change return type of the function DoWork() to MyClass, and add the WebGet-attribute as specified below. The BodyStyle Bare means "Both requests and responses are not wrapped" - we really want nothing more than a true JSON-response. The ResponseFormat should of course be "Json".
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Alaz.DotNetDiscoveries.JSONWithWCF
{
// NOTE: If you change the interface name "ITrueJSON" here, you must also update the reference to "ITrueJSON" in Web.config.
[ServiceContract]
public interface ITrueJSON
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
MyClass DoWork();
}
}
- Lets look at the class TrueJSON, change the return type of DoWork() to MyClass, and create something to return:
namespace Alaz.DotNetDiscoveries.JSONWithWCF
{
// NOTE: If you change the class name "TrueJSON" here, you must also update the reference to "TrueJSON" in Web.config.
public class TrueJSON : ITrueJSON
{
public MyClass DoWork()
{
var returnObject = new MyClass
{
Id = 1,
IHaveNoDataMemberAttribute = "Meaningless",
Name = "Satchmo",
NoPublicGet = "Hello world!",
InternalProperty = 155
};
return returnObject;
}
}
}
- If you try to run the service and call it with url TrueJSON.svc/DoWork (we did actually with WebGet specified we wanted to use Get-calls) nothing happens, no response at all, not even "not found". We need to continue to web.config and make some adjustments.
- In web config, start with changing "wsHttpBinding" to "webHttpBinding" (we are not working with Web Services now), then add the whole <endpointBehaviors> section below with our self-named behavior "JsonBehavior". Now add the behaviorConfiguration="JsonBehavior" attribute to the service-tag.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="Alaz.DotNetDiscoveries.JSONWithWCF.TrueJSONBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="JsonBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="Alaz.DotNetDiscoveries.JSONWithWCF.TrueJSONBehavior" name="Alaz.DotNetDiscoveries.JSONWithWCF.TrueJSON">
<endpoint address="" binding="webHttpBinding" contract="Alaz.DotNetDiscoveries.JSONWithWCF.ITrueJSON" behaviorConfiguration="JsonBehavior">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
- Ok, time to try it out, start the project and point the url to TrueJSON.svc/DoWork. Save the file (add .txt for convenience) then open in notepad. The result reads: {"Id":1,"InternalProperty":155,"Name":"Satchmo","NoPublicGet":"Hello world!"} and all is well! If you examine the headers, you will see: Content-Type: application/json; charset=utf-8 and that is really good to.
- By default, WCF services lives outside the ASP.NET pipeline, so without more configuration, you have no HttpContext.Current, authorization, impersonation and so forth. To enable it, look at the article "Enabling HttpContext in WCF Services".
That was one method to do it, an alternative way to make WCF Service return true JSON is described in "Return JSON from Ajax-enabled WCF Service".