maandag 28 februari 2011

Show popup under text in rich textbox control in silverlight

Show popup under text in TextBox
I had a question the other day about someone who wanted to add a popup menu under a certain line / word of text.  Here is the solution:
In the XAML we have the following markup:
    <Grid>
        <RichTextBox x:Name="richtTextBox" Height="400" VerticalAlignment="Top"/>
        <Button HorizontalAlignment="Left" VerticalAlignment="Bottom" Click="testButton_Click" Content="qdfsdfsfsdf"/>
    </Grid>

Then in the constructor of the page I insert some text in the textbox:
richtTextBox.Selection.Text =
        "Lorem ipsum pro falli dicunt volumus te, ex velit probatus corrumpit per. His ex reque aperiam alienum, liber indoctum per an. Sed ei nibh cibo minim, et eam graeci suavitate. Vim iusto gubergren repudiandae ei.";

Then when the user clicks the button, the popup opens up under the selected text:
private void testButton_Click(object sender, RoutedEventArgs e)
{
    var rect = richtTextBox.Selection.Start.GetCharacterRect(System.Windows.Documents.LogicalDirection.Forward);
    var richtTextBoxPosition =
        richtTextBox.TransformToVisual(Application.Current.RootVisual).Transform(new Point(0, 0));

    var popup = new Popup()
                    {
                        HorizontalOffset = richtTextBoxPosition.X + rect.X,
                        VerticalOffset = richtTextBoxPosition.Y + rect.Y + richtTextBox.FontSize,
                        Height = 150,
                        Width = 100
                    };
    popup.Child = new ListBox()
    {
        Background = new SolidColorBrush(Colors.Red),
        Height = 150,
        Width = 100
    }; // use your custom UC here
    popup.IsOpen = true;
}

You can tweak the code and set the selection in code behind so.
Have fun and till next post.

vrijdag 25 februari 2011

Adding metadata to RIA service calls

How to add metadata to RIA service calls
How often does it occur that you need to send some metadata which each operation.  This could be some authorization info, client parameters or what have you.  Adding a parameter to each operation is tedious and mind numbing work.  Good thing that there is always a lazy solution. ;)
One thing to keep in mind when programming with RIA services is that it generates a REST based service.  I hear people thinking: “what do I care”.  Well, you should care allot.  It means using SOAP headers to transport extra metadata is out of the question.   There is a solution for this though.  We can still use the HTTP header of the GET/PUT/POST requests to provide the service of more data.  In order to do this, we must realize that RIA services is nothing more than WCF with some added abstraction.  So we can use whatever techniques we are used to in WCF in RIA services. 
Getting down to business
Client side
At first we should inject the users data into the httpHeader when making a request to the service.  We can do this by extending the generated DomainContext class.  This class contains a partial method called OnCreated.  To add behavior to our context object, we will need to extend this method.  We should then access our proxy object to the service.  This is a property in our DomainContext class called DomainClient.  And once we have our proxy, we are on familiar terms and we can start extending it. Below is the code:
    public sealed partial class DomainService
    {
        private void OnCreated()
        {
            dynamic webDomainClient = (WebDomainClient<IDomainServiceContract>)DomainClient;
            ContextFlowEndpointBehavior contextFlowEndpointBehavior = new ContextFlowEndpointBehavior();
            webDomainClient.ChannelFactory.Endpoint.Behaviors.Add(contextFlowEndpointBehavior);

        }
    }
To be able to intercept every call to the service we will need to create a message inspector.  In the message inspector we can modify our request message that is going to be sent to the service.  In this case we will add some parameters to the HttpHeader:
public class ContextFlowEndpointBehavior : IEndpointBehavior
{


    public void IEndpointBehavior_Validate(ServiceEndpoint endpoint)
    {
    }
    void IEndpointBehavior.Validate(ServiceEndpoint endpoint)
    {
        IEndpointBehavior_Validate(endpoint);
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }


    public void IEndpointBehavior_ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }
    void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        IEndpointBehavior_ApplyDispatchBehavior(endpoint, endpointDispatcher);
    }


    public void IEndpointBehavior_AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }
    void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        IEndpointBehavior_AddBindingParameters(endpoint, bindingParameters);
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
    }

    public void IEndpointBehavior_ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new ContextFlowMessageInspector());
    }
    void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        IEndpointBehavior_ApplyClientBehavior(endpoint, clientRuntime);
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

public class ContextFlowMessageInspector : IClientMessageInspector
{

    public object IClientMessageInspector_BeforeSendRequest(ref Message request, IClientChannel channel)
    {

        string myHeaderName = "foo";
        string myheaderValue = "bar";

        HttpRequestMessageProperty prop = (HttpRequestMessageProperty)request.Properties(HttpRequestMessageProperty.Name);
        prop.Headers(myHeaderName) = myheaderValue;
        return null;
    }
    object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        return IClientMessageInspector_BeforeSendRequest(request, channel);
    }



    public void IClientMessageInspector_AfterReceiveReply(ref Message reply, object correlationState)
    {
    }
    void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
    {
        IClientMessageInspector_AfterReceiveReply(reply, correlationState);
    }
}


Server side
Once we’re done injecting into the HttpHeader of the request client side, we have to be able to read the HttpHeader before it processed by the service.  We can do this by adding another message inspector and extracting the information like this:
public class OperationBehaviorAttribute : Attribute, IOperationBehavior
{


    public void Validate(OperationDescription operationDescription)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        if (dispatchOperation.Parent.MessageInspectors.OfType<ClientCustomHeadersDispatchMessageInspector>.Count == 0)
        {
            ClientCustomHeadersDispatchMessageInspector inspector = new ClientCustomHeadersDispatchMessageInspector();
            dispatchOperation.Parent.MessageInspectors.Add(inspector);
        }

    }


    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }


    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }
}

   public class ClientCustomHeadersDispatchMessageInspector : IDispatchMessageInspector
    {

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {

            string foo = HttpContext.Current.Request.Headers("foo");
            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }
    }

Then when you have this data, whatever you want to do with it is up to you…  One of the things I like to do is add the parameter to the cache of the httpContext.  This proves to be very usefull when it is always the same data that is being sent to your service.  Eg: I had to write an application that required the user to log in with a smart card.  Legal issues prevented us from saving the data and we didn’t want to bother the user by forcing him to keep his card inserted.  We cached the card’s data and added the id of the data in the http header.
There are a few downsides to this approach though.  One problem is security.  You need to secure the channel in which your messages are being sent when dealing with sensitive data.  Everyone can read a httpHeader with fiddler.
Another problem is that some browsers (mainly firefox and chrome) encapsulate the Silverlight plugin.  This causes some issues when your Silverlight application tries to write inside the httpheader.  However there is a solution for this.  You can specify that the client handles the HTTP, this allows you finer control over the http calls. (http://msdn.microsoft.com/en-us/library/dd920295%28v=vs.95%29.aspx)
Add this in the constructor of your App.xaml:
WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp)

Here are the advantages and disadvantages summed up
Advantages:
  • Transparent
  •  Eliminates redundant code
Disadvantages:
  • Security
  • Chrome / firefox issues
Hope this proves useful.
Till next time ;-)

donderdag 24 februari 2011

First Post

Pffffft... first blog post, this is going to be tricky.

So let me start of by introducing myself.  My name is Luc Bos.  I'm a 23 year old nerd who is currently employed by Qframe, a daughter company of Cronos.   I work there as a Junior Consultant, or as Juval Lowy would say, I'm a code monkey.

I've been programming since I was 14 years old.  I first started writing some silly games in Dark Basic (Basic language written uppon a graphical engine) then switched over to assembly for microcontrollers (8051, PIC 16f84) and then got into the microsoft world of VB6, VB.NET and C#.  I've been writing in .NET since version 1.1 and I'm still hoocked on it (and no I am not suicidal).

The reason I am writing this blog is to share with you my day to day misery wich I encounter by writing code.  I know how devastating it can be for your blood pressure, trying to find that tedious bug that you know just isn't your faulth.  Also, since I'm a junior consultant in a progressive company, I get to play with a whole bunch of new technologies.  So I will be posting an article every now and then trying to give you my findings and opinions about these technologies.  Just to give you a taste, I will be posting a small article about WordML (OpenXml) and best practice document generation with it.

I also appreciate  any comments and thoughts on what I will be posting.  I'm still a joungster in a field filled with crazy people, so I hope to be learning from any of you.  If you do not aggree with anything that is said in this blog, I invite you to tell me your thoughts!  Probably talking to myself right now so I will be ending my first post here, till next time...

ps: I am not a native speaking english, as you might have guessed by the spelling mistakes...