Wednesday, August 26. 2009Transfer and bind a image as byte array to a silverlight application
This sample shows how to bind a image to a silverlight application when the image is transfered within a wcf service as a byte array.
1. Create a new silverlight projectCreate a new Silverlight prjeject, and choose Hoste the silverligth application in a new website. Then add a Silverlight-enabled WCF Service to the web project. 2. Create the serviceIn the service class there is an operation contract which returns an object with two properties. Since i'm quite lazy, the DataContract class is defined in the same file. namespace SLBindBinaryImage.Web { [ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class Service1 { [OperationContract] public ImageClass GetImage() { FileStream fs = File.OpenRead(@"c:\project\Kaderli\Silverlight\SLBindBinaryImage\SLBindBinaryImage.Web\img.jpg"); byte[] data = new byte[fs.Length]; fs.Read(data, 0, data.Length); ImageClass ic = new ImageClass { FileName = "img.jpg", ImageFile = data }; return ic; } } [DataContract] public class ImageClass { [DataMember] public string FileName { get; set; } [DataMember] public byte[] ImageFile { get; set; } } } 3. Bind the image within the SL applicationI just add one Image and one TextBox control to the xaml. The importent thing is to add a Resource to to the grid which is responsible for converting my byte array intot the image. <UserControl x:Class="SLBindBinaryImage.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SLBindBinaryImage" mc:Ignorable="d" Width="600" d:DesignHeight="480"> <Grid x:Name="LayoutRoot"> <Grid.Resources> <local:BinaryArrayToURIConverter x:Key="binaryArrayToURIConverter" /> </Grid.Resources> <StackPanel> <Button x:Name="btnLoadImage" Content="Get image" Click="btnLoadImage_Click"> </Button> <TextBlock x:Name="txtImageName" Text="{Binding FileName, Mode=OneWay}"></TextBlock> <Image x:Name="img" Height="300" Source="{Binding ImageFile,Converter={StaticResource binaryArrayToURIConverter}}"></Image> </StackPanel> </Grid> </UserControl> In this sample i only implemented the Convert method. Now if the binding of the Image takes place, this Convert methode is called, and the BitmapImage is bound to the control. using System; using System.Globalization; using System.IO; using System.Windows.Data; using System.Windows.Media.Imaging; namespace SLBindBinaryImage { public class BinaryArrayToURIConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { MemoryStream ms = new MemoryStream((byte[])value); BitmapImage image = new BitmapImage(); image.SetSource(ms); return image; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } 4. Links and downloadsolution to download(Silverlight 3) IValueConverter StaticResource
Posted by suntsu
in work
at
15:10
| Comments (0)
| Trackbacks (0)
Defined tags for this entry: Silverlight
Friday, August 21. 2009Using a Businessobject in Silverlight from client and server
Following situation:
I have a BusinessObject called Person which i want to use in a Silverlight project. This Buisnessobject should be returned from a WCF service and should have some functionality on it. Now, if i define this object on the WCF service, i can use it only as DTO, but i cannot add additional functionality on it(Or at least i am unable to use it in a silverlight application). Now, i'm showing a way how you can get all this requirements done. 1. Create a new silverlight projectJust create a Silverlight 3.0 project. Im using the visual studio built in webserver for providing the xap file as well as for the WCF service. 2. Create the business object and the wcf serviceNow, just add a Silverlight enabled webservice to the web project. In this newly added service1.cs, i add a new method GetPerson and a new class Person which will be my Businessobject/Datatransverobject for this sample. I have put the Person class into the same file. [ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class Service1 { [OperationContract] public Person GetPerson() { return new Person() {FirstName = "manuel", LastName = "kaderli", Salutation = "Dear Mr. "}; } } [DataContract] public class Person { [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } [DataMember] public string Salutation{ get; set; } } This service is ready to use, and i now add a service reference on the silverlight project. 3. Use the service from silverlightOn the xaml page, i add a button and some TextBlocks. I'm using the Binding mechanism for get/set data to the controls. <UserControl x:Class="SilverlightBusinessObject.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" Width="640" > <Grid x:Name="LayoutRoot"> <StackPanel> <Button x:Name="btnGetPerson" Content="GetPerson" Click="btnGetPerson_Click"></Button> <TextBlock x:Name="txtFirstName" Text="{Binding FirstName, Mode=TwoWay}"></TextBlock> <TextBlock x:Name="txtLastName" Text="{Binding LastName, Mode=TwoWay}"></TextBlock> <TextBlock x:Name="txtSalutation" Text="{Binding Salutation, Mode=TwoWay}"></TextBlock> </StackPanel> </Grid> </UserControl> The csharp file does only call the service, and bind the person object to the LayoutRoot. public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void btnGetPerson_Click(object sender, RoutedEventArgs e) { Service1Client sc = new Service1Client(); sc.GetPersonCompleted += new EventHandler<GetPersonCompletedEventArgs>(sc_GetPersonCompleted); sc.GetPersonAsync(); } void sc_GetPersonCompleted(object sender, GetPersonCompletedEventArgs e) { Person person = e.Result; LayoutRoot.DataContext = person; } } When i now run this application, and after pressing the button it shows me the values of the three properties which are bound to the xaml. 4. Addin functionality to the person BusinessObjectI want to add a new control to the page, which should display the full letter salutation, in my sample this would be "Dear Mr. Kaderli Manuel". Of course i could do this right on the silverlight page. But this functionality belongs to the BusinessObject. Since the person object is sent via wcf, there is no possibility of code sharing. And i don't want to edit any generated proxy files. What i now want to is to share the person BusinessObject between the web/wcf server and the silverlight application. But because they don't use the same .net framework(web/wcf uses .net 3.5 and the silverlight application obviously the silverlight framework) which are incompatible. First i add a new project of type Silverlight Class Library to my solution. Then i move the Person class which is in the .svc service file into a seperate class in the newly created class library project. Now i can add the method GetLetterSalutatioin to this class. Make sure to include System.Runtime.Serialization with the using statement. using System.Runtime.Serialization; namespace BusinessDTO { [DataContract] public class Person { [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } [DataMember] public string Salutation { get; set; } public string LetterSalutation { get { return string.Format("{0} {1} {2}", Salutation, LastName, FirstName); } } public void DoSomethiing() { //add any other businesslogic here } } } Since i have remove this code from the web/wcf project there are now some errors, because tihs class is missing. I just add this Person class as link. Just select add existing item, select the Person class from the silverlight class library project, and make sure to use add as link. In the .svc file, i just have to add the new namespace: using BusinessDTO; In the silverlight project, it's even easier. Just add the BusinessObject project as a project reference. Make sure to renew the service reverence on the silverlight application, in order to get the latest proxy. I had first to delete the existing service reference, and the to add it again to get it working. Now, i'm able to write the following in the silverlight client: BusinessDTO.Person person = e.Result; string letterSalutatioin = person.LetterSalutation; person.DoSomethiing(); Now i have clientside a object wihch comes from a wcf service but which also can have business functionality. It is also possible to use the new property LetterSalutation as source for a control. <TextBlock x:Name="txtLetterSalutation" Text="{Binding LetterSalutation, Mode=OneWay}"></TextBlock> 5. Use specific functionality client or serversideBecause i use the code from a silverlight class library now in a silverlight project as well as in a .net 3.5 project, there may be some problems. E.g. some functionality like ObservableCollection are not in the same assmbly in the .net 3.5 framework and in the silverlight framework. Then you might have situations where you like to have code for either client or serverside. For this you can use #if SILVERLIGHT statement in the BusinessObjects classes. #if SILVERLIGHT //code available only for silverlight applicatioins #else //code available for web/wcf service #endif You can get the whole solution right here. Now, this is the way i'm working with BusinessObjects and silverlight/wcf. If one has a remark, or an other solution, please leave a commen. cheers
Posted by suntsu
in Silverlight, WCF, work
at
16:03
| Comments (0)
| Trackbacks (0)
Defined tags for this entry: silverlight, wcf
Wednesday, July 22. 2009Silverlight/WCF starter solution (not for dummies)
It took me several days to create a proper solution fundament for silverlight, so i decided to publish my starter solution. Maybe it helps some of you.
There is a solution available for download for each of the four parts. I had the following requirements:
Let's start. I'm going to implement each of this topic separately, and hopefully get a solution working till this blog entry is finish. Initialize solution I just start with a new Silverlight solution in visual studio 2008. The only thing i change from original, is to assign a static port to the built in web server. This makes the life with wcf much easier. Then add a new Silverlight-enabled WCF Service to the web project, create some operation contract, and add a service reference to the silverlight project. 1. Session management (with aspNetCompatibilityEnabled)For this, there are two possibilities: 1. Do it yourself (Write something like a session agent service) 2. Use the ASP session management I guess there are lots of reasons not to use aspNetCompatibility (The most obvious might be performance), but the simplicity of it was the reason for me to choose it anyway. I have to say that i did not invent this, i just copied it from an article of SpoonStomper from the silverlight forum. The following goal i want to achieve. I press a button on my silverlight application which sends a string to my service. Then i want to press another button and get back this string again(Sounds really easy btw.). To enable the asp session management you first have to edit the web.config <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> //this should be default since silverlight 3 On your service class, you have to change the RequirementsMode from Allowed to Required [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] public class MyCoolService{. With this modification, you're ready to go. Now you can use the HttpContext.Current.Session for handling session stuff. [OperationContract] public void ServiceCallOne(string message) { HttpContext.Current.Session["Test"] = message; } [OperationContract] public string ServiceCallTwo() { return (string)HttpContext.Current.Session["Test"]; } You can download the solution with activated asp session management from here Make sure to use my .suo file, since the service settings are stored in this file. Impersonate userThe user impersonation is build on top of the previous topic. Since we are asp.net controlled, we can use the HttpContext to impersonate. Here you can find the description from microsoft [OperationContract] public string WhoAmIAfterImpersonate() { ((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate(); return HttpContext.Current.User.Identity.Name; } After the Impersonate, the service stuff will be executed as the user who has called it. Btw. as far as i understand, this requires ntlm authentication. To get this in firefox without being asked for username and password, have a look here You can download the solution with Impersonate from here Error handlingSince it is not possible to catch regular exception from a wcf service in a silverlight application, there is another way to do it. I just explain it in a short story, and give the example. You may find the whole story from microsoft here. First: Create a FaultBehavior class in your web project: using System; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Configuration; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; using System.Web; namespace SilverlightWCF.Web { public class MyFaultBehavior : BehaviorExtensionElement, IEndpointBehavior { public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { SilverlightFaultMessageInspector inspector = new SilverlightFaultMessageInspector(); endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector); } public class SilverlightFaultMessageInspector : IDispatchMessageInspector { public void BeforeSendReply(ref Message reply, object correlationState) { if (reply.IsFault) { HttpResponseMessageProperty property = new HttpResponseMessageProperty(); // Here the response code is changed to 200. property.StatusCode = System.Net.HttpStatusCode.OK; reply.Properties[HttpResponseMessageProperty.Name] = property; } } public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { // Do nothing to the incoming message. return null; } } // The following methods are stubs and not relevant. public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void Validate(ServiceEndpoint endpoint) { } public override System.Type BehaviorType { get { return typeof(MyFaultBehavior); } } protected override object CreateBehavior() { return new MyFaultBehavior(); } } } Second: Edit the web.config <system.serviceModel> <!--Add a behavior extension within the service model--> <extensions> <behaviorExtensions> <add name="myFault" type="SilverlightWCF.Web.MyFaultBehavior, SilverlightWCF.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </behaviorExtensions> </extensions> ... <behaviors> <!--Add a endpointBehavior below the behaviors--> <endpointBehaviors> <behavior name="myFaultBehavior"> <myFault/> </behavior> </endpointBehaviors> ... <!--Set the behaviorConfiguration of the endpoint--> <endpoint address="" binding="customBinding" bindingConfiguration="customBinding0" contract="SilverlightWCF.Web.MyCoolService" behaviorConfiguration="myFaultBehavior" /> ... <!--For debugging, it might be cool to have some more error information. to get this, set includeExceptionDetailInFaults to true--> <serviceDebug includeExceptionDetailInFaults="true" /> Third: Create an operation contract which throws an exception. Make sure not to throw regular exception, but FaultException Fourth: Handle the error within your silverlilght application private void btnThrowException_Click(object sender, RoutedEventArgs e) { serviceClient.ThrowExceptionCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(serviceClient_ThrowExceptionCompleted); serviceClient.ThrowExceptionAsync(); } void serviceClient_ThrowExceptionCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { if (e.Error == null) { // In case of success } else if (e.Error is FaultException) { FaultException fault = e.Error as FaultException; txtThrowException.Text = e.Error.Message; } } You can download the solution with error handling from here. Unit test the the wcf service (using sessions)Here i have to say, to unit test a single wcf method is not that difficult(its like if you unit test a library). But if you use the asp.net session to store information, the client(browser) handles this with cookies. If you want to unit test a method which needs a value from the session, you have to handle the cookies manually. Here you can find a very good explanation for handling cookies in asmx/wcf services. First you have to create a unit test project. I had to do this by hand, since create unit test on a method did not create a new project. Then use Add service reference to add a reference of the web/wcf project to your unit test project. Now implement the test methode: [TestMethod] public void TestMethod1() { string _sharedCookie = string.Empty; //Creates connection to the WCF service //It's done by code, not via config file //The config file would be overwritten all the time EndpointAddress objEndpoint = null; CustomBinding cb = new CustomBinding(); //binding depends how your web server is set up BinaryMessageEncodingBindingElement bmebe = new BinaryMessageEncodingBindingElement(); //TextMessageEncodingBindingElement tebe = new TextMessageEncodingBindingElement(MessageVersion.Default, Encoding.UTF8); HttpTransportBindingElement htbe = new HttpTransportBindingElement(); cb.Elements.Add(bmebe); cb.Elements.Add(htbe); objEndpoint = new EndpointAddress("http://localhost:11111/MyCoolService.svc"); MyCoolServiceClient _serviceClient = new MyCoolServiceClient(cb, objEndpoint); //howto manage cookies: http://megakemp.wordpress.com/2009/02/06/managing-shared-cookies-in-wcf/ using (new OperationContextScope(_serviceClient.InnerChannel)) { _serviceClient.ServiceCallOne("my first message to the server"); // Extract the cookie embedded in the received web service response // and stores it locally HttpResponseMessageProperty response = (HttpResponseMessageProperty) OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name]; _sharedCookie = response.Headers["Set-Cookie"]; } using (new OperationContextScope(_serviceClient.InnerChannel)) { //this sets the cookie for the next service request HttpRequestMessageProperty request = new HttpRequestMessageProperty(); request.Headers["Cookie"] = _sharedCookie; OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = request; string returnValue = _serviceClient.ServiceCallTwo(); Assert.AreEqual("my first message to the server", returnValue); } } As you can see, i call two method separately, and i return with the second method the session value which was set in the first method call. You can download the solution with error handling from here. Please let me know when you find mistakes/bugs in this sample. cheers manuel
Posted by suntsu
in Silverlight, WCF, work
at
23:11
| Comments (2)
| Trackbacks (0)
Defined tags for this entry: Silverlight, WCF
Tuesday, August 5. 2008Use WCF service from a Silverlight application
At work, i'm involved in a silverlight application, and i've got my first challange.
It's not that easy to use an WCF service which is not hosted in an IIS environment right from an Silverlight application. With the help of the official Silverlight forum, i figured it out. You may download an test this sample visual studio solution. Of course you have to set up the proper environment for developing Silverlight application first. The solution contains the following project:
To test it, the following projects must be started: WCFServer, WCFPolicyServer, SilverLightTestAppWeb. With this you are ready to go. If you then see the silverlight application, and press the button, it will first call the WCFServer, and then request the WCFPolicyServer for receive the clientaccesspolicy.xml. The policy is only checked once at the first webservice call. For testing it, you may download it from here WCF.rar. Just make sure to set the proper startup projects: cheers manuel
Posted by suntsu
in Silverlight, WCF, work
at
14:01
| Comments (3)
| Trackbacks (0)
Defined tags for this entry: Silverlight, WCF
Monday, January 7. 2008SVN Mirror unter Windows einrichten
Howdi
Ich durfte auf der Arbeit ein SVN Server/Mirror aufsetzen. Da ich alles schnell wieder vergesse schreibe ich das mal hier nieder... Das ganze ist zwar im SVN RedBook ziemlich gut beschrieben, allerdings nicht fuer Windows 1. Repository erstellen: Als erstes muss das Repository erstellt werden svnadmin create C:\svnrepository\RepositoryName 2. Berechtigung vergeben Es muss ein User vorhanden sein mit dem die Synchronisation durchgefuehrt wird. Dieser User darf sonst nicht verwendet werden. 3. Hooks registrieren(kopieren)(Sind unter Erweitert vorhanden): Es braucht zwei hooks. 1. start-commit, 2. pre-revprop-change damit nur noch von einem User(Mirror-User) aenderungen am Repository vorgenommen werden koennen. 4. Mirror initialisieren "C:\Program Files\Subversion\bin\svnsync.exe" initialize http://mirror host/MirrorRepository http://master host/MasterRepository --username user --password password 5. Synchronisation starten Mit folgender Zeile wird die Synchronisation gestartet. Dies kann man auch auf dem MasterRepository als post-commit hook einrichten, damit jede aenderung sofort auf das MirrorRepository uebertragen wird. svnsync synchronize http://mirror host/MirrorRepository --username user --password password Will man auf sourcen des MirrorRepositorys aenderungen mittels svn switch --relocate auf das MasterRepository commiten, muss man dafuer die UUID des MirrorRepository gleich der UUID des MasterRepository setzen. Dafuer muss man sich zuerst eine Textdatei uuid.txt anlegen, und folgenden Text reinschreiben: SVN-fs-dump-format-version: 2 UUID: 65390229-12b7-0310-b90b-f21a5aa7ec8e UUID natuerlich mit der UUID des MasterRepositoy ersetzen, und am Ende des files eine Leerzeile lassen(wieso auch immer) Danach kann man via cmd die UUID des MirrorRepositoy anpassen: type uuid.txt | svnadmin load --force-uuid C:\svnrepository\MirrorRepositoy cheers manuel ps: Mir ist klar das Windos boese ist, aber das habe ich auf der Arbeit nicht zu entscheiden pps: UUID unter windows aendern ist recht tricky. Unter http://www.nabble.com/svn-relocate-fails-due-to-bad-char-at-end-of-url_uuid-%3Euuid-td13716243.html ist eine Beschreibung zu finden. Continue reading "SVN Mirror unter Windows einrichten"
Posted by suntsu
in SVN, work
at
16:42
| Comments (2)
| Trackbacks (0)
Defined tags for this entry: SVN
(Page 1 of 1, totaling 5 entries)
|
QuicksearchcontactBlog abonnierenGetaggte ArtikelAktuelle Einträge
Powered byQuick linkBlog Administration |
