Social Icons

twitter google plus linkedin rss feed

Pages

10.12.12

ObservableDictionary for Silverlight

I have reused copied the code from Shimmy's Blog but had to tweak it a bit to make it fit for Silverlight. At the moment I have used it just in one of my projects but works very well.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace SLUtils.Classes
{
        public class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
        {
            private const string CountString = "Count";
            private const string IndexerName = "Item[]";
            private const string KeysName = "Keys";
            private const string ValuesName = "Values";

            private IDictionary<TKey, TValue> _Dictionary;
            protected IDictionary<TKey, TValue> Dictionary
            {
                get { return _Dictionary; }
            }

            #region Constructors
            public ObservableDictionary()
            {
                _Dictionary = new Dictionary<TKey, TValue>();
            }
            public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
            {
                _Dictionary = new Dictionary<TKey, TValue>(dictionary);
            }
            public ObservableDictionary(IEqualityComparer<TKey> comparer)
            {
                _Dictionary = new Dictionary<TKey, TValue>(comparer);
            }
            public ObservableDictionary(int capacity)
            {
                _Dictionary = new Dictionary<TKey, TValue>(capacity);
            }
            public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
            {
                _Dictionary = new Dictionary<TKey, TValue>(dictionary, comparer);
            }
            public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer)
            {
                _Dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
            }
            #endregion

            #region IDictionary<TKey,TValue> Members

            public void Add(TKey key, TValue value)
            {
                Insert(key, value, true);
            }

            public bool ContainsKey(TKey key)
            {
                return Dictionary.ContainsKey(key);
            }

            public ICollection<TKey> Keys
            {
                get { return Dictionary.Keys; }
            }

            public bool Remove(TKey key)
            {
                if (key == null) throw new ArgumentNullException("key");

                TValue value;
                Dictionary.TryGetValue(key, out value);

                int index = GetIndex(Dictionary, key);
                var removed = Dictionary.Remove(key);

                if (removed)
                    OnCollectionChanged(NotifyCollectionChangedAction.Remove, new KeyValuePair<TKey, TValue>(key, value), index);
                    //OnCollectionChanged();
                return removed;
            }

            public bool TryGetValue(TKey key, out TValue value)
            {
                return Dictionary.TryGetValue(key, out value);
            }

            public ICollection<TValue> Values
            {
                get { return Dictionary.Values; }
            }

            public TValue this[TKey key]
            {
                get
                {
                    return Dictionary[key];
                }
                set
                {
                    Insert(key, value, false);
                }
            }

            #endregion

            #region ICollection<KeyValuePair<TKey,TValue>> Members

            public void Add(KeyValuePair<TKey, TValue> item)
            {
                Insert(item.Key, item.Value, true);
            }

            public void Clear()
            {
                if (Dictionary.Count > 0)
                {
                    Dictionary.Clear();
                    OnCollectionChanged();
                }
            }

            public bool Contains(KeyValuePair<TKey, TValue> item)
            {
                return Dictionary.Contains(item);
            }

            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
            {
                Dictionary.CopyTo(array, arrayIndex);
            }

            public int Count
            {
                get { return Dictionary.Count; }
            }

            public bool IsReadOnly
            {
                get { return Dictionary.IsReadOnly; }
            }

            public bool Remove(KeyValuePair<TKey, TValue> item)
            {
                return Remove(item.Key);
            }

            #endregion

            #region IEnumerable<KeyValuePair<TKey,TValue>> Members

            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
            {
                return Dictionary.GetEnumerator();
            }

            #endregion

            #region IEnumerable Members

            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable)Dictionary).GetEnumerator();
            }

            #endregion

            #region INotifyCollectionChanged Members

            public event NotifyCollectionChangedEventHandler CollectionChanged;

            #endregion

            #region INotifyPropertyChanged Members

            public event PropertyChangedEventHandler PropertyChanged;

            #endregion

            public void AddRange(IDictionary<TKey, TValue> items)
            {
                if (items == null) throw new ArgumentNullException("items");

                if (items.Count > 0)
                {
                    if (Dictionary.Count > 0)
                    {
                        if (items.Keys.Any((k) => Dictionary.ContainsKey(k)))
                            throw new ArgumentException("An item with the same key has already been added.");
                        else
                            foreach (var item in items) Dictionary.Add(item);
                    }
                    else
                        _Dictionary = new Dictionary<TKey, TValue>(items);

                    OnCollectionChanged(NotifyCollectionChangedAction.Add, items.ToArray(), GetIndex(Dictionary, items.Keys.First())); //We notify the index of the first added key
                }
            }

            private void Insert(TKey key, TValue value, bool add)
            {
                if (key == null) throw new ArgumentNullException("key");

                TValue item;
                if (Dictionary.TryGetValue(key, out item))
                {
                    if (add) throw new ArgumentException("An item with the same key has already been added.");
                    if (Equals(item, value)) return;
                    Dictionary[key] = value;

                    OnCollectionChanged(NotifyCollectionChangedAction.Replace, new KeyValuePair<TKey, TValue>(key, value), new KeyValuePair<TKey, TValue>(key, item), GetIndex(Dictionary, key));
                }
                else
                {
                    Dictionary[key] = value;

                    OnCollectionChanged(NotifyCollectionChangedAction.Add, new KeyValuePair<TKey, TValue>(key, value), GetIndex(Dictionary, key));
                }
            }

            private void OnPropertyChanged()
            {
                OnPropertyChanged(CountString);
                OnPropertyChanged(IndexerName);
                OnPropertyChanged(KeysName);
                OnPropertyChanged(ValuesName);
            }

            private int GetIndex(IDictionary<TKey, TValue> Dictionary, TKey key)
            {
                int i = 0;
                foreach (var dictKey in Dictionary.Keys)
                {
                    if (dictKey.Equals(key)) return i;
                }

                return -1;
            }

            protected virtual void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }

            private void OnCollectionChanged()
            {
                OnPropertyChanged();
                if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }

            private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> changedItem, int index)
            {
                OnPropertyChanged();
                if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem, index));
            }

            private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> newItem, KeyValuePair<TKey, TValue> oldItem, int index)
            {
                OnPropertyChanged();
                if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
            }

            private void OnCollectionChanged(NotifyCollectionChangedAction action, IList newItems, int index)
            {
                OnPropertyChanged();
                if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItems, index));
            }

            public override string ToString()
            {
                return string.Format("ObservableDictionary<{0}> Count={1}", GetKeyAndValue(Dictionary.GetType().GetGenericArguments()), Count);
            }

            private object GetKeyAndValue(Type[] Types)
            {
                string result = string.Empty;

                foreach (Type type in Types)
                {
                    result += type.ToString() + ",";
                }

                if (!string.IsNullOrEmpty(result) && result.Length > 1)
                    result = result.Substring(0, result.Length - 1);

                return result;
            }
        }
}
Give it a go and let me know how it works.

No comments:

Post a Comment

23.11.12

StratexStudio is in the Store

image
A couple of days ago we finally managed to get StratexStudio certified and published.

Our StratexLive users will be able to connect to their company site using their credentials and the StratexLive URL and start using their Surfaces to show the other board members how good their enterprises are doing and how shiny their new Windows 8 devices are.

The new application has dashboards to measure the Performance, Risks and Controls as well as the activity in the portal and a nested view of the organization hierarchy.

Have a look at the Windows Store page of the StratexStudio to get more pictures and if you have Windows 8 download it and give it a go, it’s free.

No comments:

Post a Comment

15.11.12

Click works but Tapped Crashes on Windows 8

Our app has been rejected from the store because it crashes when the user taps in a GridView. As we don’t have a proper surface we were using the simulator to test our software but with the mouse tool not with the finger and it was working perfectly…

It crashes every time you tap in an item in a GridView and it’s funny, funny peculiar, not funny ha ha, because it crashes right in the tap, the code doesn't even get to the call-back, it just crashes. The crash info is not useful, as expected.

Looks like there’s a bug in the GridView and after it’s assigned to a populated DataContext it needs to be refreshed before it accepts Taps, even though it works fine with Clicks.

There’s no way or I haven’t found it of refreshing the UI in WinRT which I reckon it will solve this issue, so I have taken two different approaches to solve this bug.

  • Fast loading dashboards: I am preloading the contents of the fast loading dashboards once the app is executed. Doing this I get all of the GridViews populated in a page that is not being displayed to the users, in the background. Once the page where the GridView is selected by the user it’s rendered along with the GridView object refreshing it.
  • Slow loading dashboards: I am preloading the contents on this dashboards too but if the user clicks them right after the app loads they will still be loading causing the GridView to render just once after the DataContext is populated. In this cases I have changed the behaviour of the dashboard and I’m assigning the DataContext before and updating it several times, once every new chunk of data is received. This way the GridView gets refreshed once per chunk of new information and the issue with the tapping is solved.

The guys at the Windows Store App Lab said they will find a proper solution to this issue but I think this is the kind of bug that will be fixed through windows update. Anyway I’ll keep you posted if they come back with something new.

***UPDATE***
A Microsoft's expert pointed out that if you create and populate the GridView in code and add it to the page  it will work as expected. I've tested this and it's true.

The templates in my GridViews are complex so I'll make them user controls so I can create and populate them in code without loosing the MVVM approach. I still haven't tested this.

No comments:

Post a Comment

6.11.12

Connecting VS2010 to the new tfs.visualstudio.com (TFS2012)

It looks cool and it’s free for 5 or less users, (looks like it will be free for bigger teams with the MSDN Subscriptions) how come we are not already using it?

We are indeed using it for our Windows Metro App but for our SharePoint 2010 code we are still using the good old TFS2010.

We have documentation about how to connect VS2010 to the new TFS but, as usual, I'm afraid it won't be that easy.

Our Visual Studios 2010 have already been updated with the Service Pack 1 so all we need now is the KB2662296.

This patch can be installed from windows update or downloaded conveniently form here.

The first time I executed the file it complained about some missing requirements. I checked that I had the SP1 installed in visual studio and it was… so ran it again and it worked the second time. Everybody knows software must work at least once every three times before it can be considered ready to be delivered.

It took a while to install and finally it required a restart of the computer.

After the installation and the restart I tried to connect to the new team project from the “Open new instance of Visual Studio” link but it didn't work.

OK, the next guess is to add the team foundation server from the VS2010 as always… CTRL+C, CTRL+V of the URL and click next… And it worked!

I can’t wait to see that burndown chart showing the team’s progress!

image

No comments:

Post a Comment

3.10.12

A Thread.Sleep that does not freeze the thread

I have been trying to add unit tests to my SharePoint code and it’s not an easy task. One of the main points I wanted to test was the ItemEventReceivers on a list. This works if you use the synchronous events such as ItemAdding or ItemUpdating but when it comes to test if the asynchronous events have taken place as expected you need to wait a bit.

Putting the test thread to sleep prevents the asynchronous events from happening (it’s on the same thread as the SharePoint code) and, even though your code is working when you are executing it manually, all of the tests fail so I have created a new class based on timers that will let the asynchronous events to trigger and execute. I call it Waiter.
public class Waiter : IDisposable
{
    public enum WaiterState
    {
        Waiting,
        TimedOut,
        Success,
        Error
    };

    System.Timers.Timer WaitTimer;
    ManualResetEvent manualResetEvent;
    int WaitCounter;

    private Waiter(int interval)
    {
        WaitCounter = 0;

        manualResetEvent = new ManualResetEvent(true);
        WaitTimer = new System.Timers.Timer() { AutoReset = false, Interval = interval };
        WaitTimer.Elapsed += new ElapsedEventHandler(WaitTimer_Elapsed);
    }

    void WaitTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        WaitCounter++;
        manualResetEvent.Set();
    }

    /// 
    /// Waits for the interval in milliseconds times number of times or once by default.
    /// 
    public static WaiterState Wait(int interval, int times)
    {
        try
        {
            using (Waiter WaiterClass = new Waiter(interval))
            {
                while (WaiterClass.WaitCounter <= times)
                {
                    WaiterClass.WaitTimer.Start();
                    WaiterClass.manualResetEvent.WaitOne();
                }
            }
        }
        catch
        {
            return WaiterState.Error;
        }

        return WaiterState.Success;
    }

    /// 
    /// Waits for the interval in milliseconds once.
    /// 
    public static WaiterState Wait(int interval)
    {
        return Wait(interval, 0);
    }

    void Dispose()
    {
        WaitTimer.Dispose();
    }
}
Give it a go.

No comments:

Post a Comment

Restarting SharePoint 2010 Timer Service Programmatically

I need to restart the Timer Service from an application and it took me some time to find the answer. It’s as easy as one could think.

Anyway here's the code:
/// 
/// Stops the SharePoint timer.
/// 
public static void TimerStop()
{
    ServiceController timerService = new ServiceController(Constants.SPTimerName);

    if (timerService.Status == ServiceControllerStatus.Running)
    {
        timerService.Stop();
        timerService.WaitForStatus(ServiceControllerStatus.Stopped, Constants.WaitingTimeout);
    }
}

/// 
/// Starts the SharePoint timer.
/// 
public static void TimerStart()
{
    ServiceController timerService = new ServiceController(Constants.SPTimerName);

    if (timerService.Status == ServiceControllerStatus.Stopped)
    {
        timerService.Start();
        timerService.WaitForStatus(ServiceControllerStatus.Running, Constants.WaitingTimeout);
    }
}
And by the way the constants are:
public static TimeSpan WaitingTimeout = new TimeSpan(0, 1, 30);
public static string SPTimerName = "SharePoint 2010 Timer";

No comments:

Post a Comment

17.9.12

Cannot import the following key file error in VS2012

I don’t know if this works as well in VS2010 or 2008 but in VS2012 is really easy to add the key to the pfx file.

If you are getting the infamous error:
Cannot import the following key file: <FileName>.pfx. The key file may be password protected. To correct this, try to import the certificate again or manually install the certificate to the Strong Name CSP with the following key container name: VS_KEY_<A Key>

You can solve it easily by:

Clicking properties in the project that contains the file that is causing the issue.

image

Then going to "Signing" and select again the file. You will be prompted for the password.

image

Enter the password and you are done.

No comments:

Post a Comment

6.9.12

Authenticating an ASMX Web Service in SharePoint from a WinRT app

Where’s the CookieContainer?

Yes mate, I’ve had that question too.

We are creating a new application for Windows 8 and we need it to connect to our web services. Connecting to the anonymous methods was easy, but when it comes to authenticating the user the situation changes.

I was pretty confident, in this context confident is an euphemism for ignorant and naive,  I could use the same approach I used when I was creating my apps for WP7 I have used it a thousand times and WP7 is more or less the same as WinRT so who would have thought it won’t work?
Well WinRT is not the same as WP7.

After creating the SPAuthBridge class I tried to add the authentication cookie to my SoapClient as usual but as you probably now if you are reading this post this line doesn’t work:

MySoapClient.CookieContainer = SharePointAuth.cookieJar;

In WinRT the SoapClient object doesn’t have a CookieContainer object so we have to find another way of adding the cookie in the calls.

The SPAuthBridge is OK. I have just added a new method to it to get the authentication cookie as string from the cookie container.
public string GetAuthenticationCookie()
{
    return string.Format("{0}={1}", "FedAuth",
            cookieJar.GetCookies(new System.Uri("https://www.mySite.com"))["FedAuth"].Value);
}

Then all you have to do is to follow the steps in the previous post to authenticate and after you have successfully authenticated to SharePoint you have to change the way you add the cookie to your SoapClient.

I have found two ways:

The quick one

Every time you need to call the web service you have to add the cookie to the header and then call the web service in the same OperationContextScope. It looks like this:
using (new OperationContextScope(MyWS.InnerChannel))
{
    HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();

    httpRequestProperty.Headers[System.Net.HttpRequestHeader.Cookie] = SharePointAuth.GetAuthenticationCookie();

    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

    UserInfo = await MyWS.GetInfoForUserAsync();
}

That’s easy but it’s not very readable and if you have to call a lot of web services you’ll probably get bored of this approach.

The elegant one

Instead of manually adding the cookie every time we can also create a behaviour that does it automatically.

In order to do that you need to create a CookieBehavior class. I copied 99% of mine from here and it looks like this:
class CookieBehaviour: IEndpointBehavior
{
    private string cookie;

    public CookieBehaviour(string cookie)
    {
        this.cookie = cookie;
    }

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

    public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
    {
        behavior.ClientMessageInspectors.Add(new CookieMessageInspector(cookie));
    }

    public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint,
        EndpointDispatcher endpointDispatcher) { }

    public void Validate(ServiceEndpoint serviceEndpoint) { }
}

public class CookieMessageInspector : IClientMessageInspector
{
    private string cookie;

    public CookieMessageInspector(string cookie)
    {
        this.cookie = cookie;
    }

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

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        HttpRequestMessageProperty httpRequestMessage;
        object httpRequestMessageObject;
        if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name
            , out httpRequestMessageObject))
        {
            httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
        }
        else
            httpRequestMessage = new HttpRequestMessageProperty();

        httpRequestMessage.Headers[System.Net.HttpRequestHeader.Cookie] = cookie;
        request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);

        return null;
    }
}

Once you have this class the only thing you have to do is to add this behaviour to your web service on the initialization and your cookie will be added automatically every time.
public MyWSSoapClient InitializeMyWS()
{
    BasicHttpBinding Bind = new BasicHttpBinding();

    //////////////////////Transport///////////////////////
    Bind.Security.Mode = BasicHttpSecurityMode.Transport;
    //////////////////////////////////////////////////////

    /////////////////////MessageSize//////////////////////
    Bind.MaxReceivedMessageSize = Int32.MaxValue;
    //////////////////////////////////////////////////////

    EndpointAddress oAddress = new EndpointAddress(SiteUrl + "/_vti_bin/MyWS.asmx");
    MyWSSoapClient MyWS = new MyWSSoapClient(Bind, oAddress);

    CookieBehaviour AuthCookieBehaviour = new CookieBehaviour(SharePointAuth.GetAuthenticationCookie());
    MyWS.Endpoint.EndpointBehaviors.Add(AuthCookieBehaviour);

    return MyWS;
}

After you have initialized the web service like this you can call your methods without worrying about the authentication any more:
private async Task<ObservableCollection<Info>> GetInfo()
{
    GetInfoForUserResponse Information = await MyWS.GetInfoForUserAsync();

    return Information.Body.GetInfoForUserResult;
}
The transport is necessary in my case because I am calling a web service hosted in an HTTPS web application by default is set to None and I was getting an ArgumentException like this:

The provided URI scheme 'https' is invalid; expected 'http'.

And the MaxReceivedMessageSize could also be a wee bit excessive. Tune it to suit your needs but be aware that if you set it too small you’ll get a nice CommunicationException saying that:

The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.

Have fun with the tablet if you have one, I am still waiting for mine.

9 comments:

Post a Comment

5.9.12

Dependency Property with Call-back and default value snippet

For me this is the way Microsoft should have created the DependencyProperty snippet from the beginning.
I use this one a lot and it has a placeholder for the default value and the call-back method I am even assigning the instance that called the call-back to a property in the snippet.
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
 <CodeSnippet Format="1.0.0">
  <Header>
   <Title>Dependency Property With CallBack</Title>
   <Shortcut>propdpCallBack</Shortcut>
   <Description>Creates a dependency property with it's callback method</Description>
   <Author>Jose Sanchez</Author>
   <SnippetTypes>
    <SnippetType>Expansion</SnippetType>
    <SnippetType>SurroundsWith</SnippetType>
   </SnippetTypes>
  </Header>
  <Snippet>
   <Declarations>
    <Literal>
     <ID>PublicName</ID>
     <Default>PropertyName</Default>
     <ToolTip>Public name of the depencency property</ToolTip>
    </Literal>
    <Literal>
     <ID>type</ID>
     <Default>string</Default>
     <ToolTip>Type of the property</ToolTip>
    </Literal>
    <Literal>
     <ID>ParentClassType</ID>
     <Default>UserControl</Default>
     <ToolTip>Type of the parent class of the dependency property</ToolTip>
    </Literal>
    <Literal>
     <ID>DefaultValue</ID>
     <Default>string.Empty</Default>
     <ToolTip>Default value of the dependency property</ToolTip>
    </Literal>
    <Literal>
     <ID>CallBackName</ID>
     <Default>PropertyCallBackName</Default>
     <ToolTip>Name of the callback method that will be triggered when the depencency property has changed</ToolTip>
    </Literal>
   </Declarations>
   <Code Language="csharp"><![CDATA[public $type$ $PublicName$
        {
            get { return ($type$)GetValue($PublicName$Property); }
            set { SetValue($PublicName$Property, value); }
        }

        // Using a DependencyProperty as the backing store for $PublicName$.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty $PublicName$Property =
            DependencyProperty.Register("$PublicName$", typeof($type$), typeof($ParentClassType$), new PropertyMetadata($DefaultValue$, new PropertyChangedCallback($CallBackName$)));


 private static void $CallBackName$(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            $ParentClassType$ Changed$ParentClassType$ = (obj as $ParentClassType$);

            //TODO: Implement some actions in Changed$ParentClassType$
        }]]>
   </Code>
  </Snippet>
 </CodeSnippet>
</CodeSnippets>
I hope you find it as useful as I do.

By the way, you can find more info about how creating and importing your code snippets here.

No comments:

Post a Comment

5.4.12

Hiding Edit in Datasheet in the Actions Menu with javascript code

Coming back after all this time to write such an ugly post? That’s exactly my style…
Well, the title of the post explains very well what was the objective and everybody knows that this is not the best way, but editing the permissions was causing issues somewhere else so we decided to do this.
This is the enemy:
Edit in Datasheet
And in order to hide it we added a Content Editor Web Part and then clicked in the Source Editor Button:
Content Editor Web Part Source Editor
There we added this script:
<script type="text/javascript" >
var allMenuItems = document.getElementsByTagName('ie:menuitem'); 
for(var i = 0; i < allMenuItems.length; i++ )   
{
 try
        {
         if (allMenuItems[i].text.toLowerCase() == "edit in datasheet")
         {
   var parentNodeOfMenuItem = allMenuItems[i].parentNode;  
                 parentNodeOfMenuItem.removeChild(allMenuItems[i]);                                
  }
 }
 catch(err)
 {}

} 
</script>

It could look a bit weird, but SharePoint won’t mind. Then we should click Save.
CEWP Source Editor Window
After that, in the Appearance group of the web part we could change the parameter Chrome Type to “None” (Or Layout –> Hidden) to make the CEWP invisible to the users.
And that’s all.
Edit in Datasheet Hidden
Enjoy!

No comments:

Post a Comment

25.2.12

CrossDomain SecurityException accessing my Azure WCF Service from Silverlight

Just uploaded a WCF Service Web Role to Azure with the intention of accessing it from a Silverlight web part, but I got the dreaded and almost expected:
System.ServiceModel.CommunicationException: An error occurred while trying to make a request to URI 'http://localhost:81/MyService.svc'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details. ---> System.Security.SecurityException ---> System.Security.SecurityException: Security error.
Yes, cool, but how do I add my crossdomain.xml or my clientaccesspolicy.xml files to an “Azure Web Role” which I just heard exists?

To my surprise it’s very easy you just have to add the XMLs to the project:

adding crossdomain.xml and clientaccesspolicy.xml to azure web role

Then you’ll be able to debug and, after you “Upgrade” the package in Azure Hosted service, you’ll be able to access it from Silverlight.

By the way, I don’t like "Upgrade" here, I find it misleading. I would have used Update.

No comments:

Post a Comment

20.2.12

MessageBox, DialogBox and Popup windows in Silverlight with the ChildWindow control

I know this has been around since Silverlight 3, but I didn’t know about it! Really? I can't believe it!

So for me is new and it looks great. In the past I have created user controls for this, but this ChildWindow has even animations…

To create it is as simple as adding a new item of this class to the project:

Create a new Silverlight Child Window
And then, tweak a bit the XAML to make it look the way you need and that’s all.

To use it you just have to create it and show it like this:
MessageWindow window = new MessageWindow("Info!", string.Format("This is a ChildWindow example."), true);
window.Show();

As always, there’s a catch. Unlike the MessageBox it won’t stop the thread waiting for your reply (this is also good in some cases, I have found lately that the MessageBox dialogs are quite resource cosuming) so if you want to use the response the user has selected in your ChildWindow you should subscribe to the Close event, something like this:
MessageWindow window = new MessageWindow("Info!", string.Format("This is a ChildWindow example."), true);
window.Show();

window.Closed += (sndr, args) =>
{
    if (window.DialogResult == true)
    {
        StratexWS.GetFBAUsersAsync();
        LoadingWindow.Show();
    }
};

I have tweaked a bit the OOTB code. Mine looks like this:

ChildWindow example
By the way, there’s at least another catch, it won’t work in the constructor… it only works after the control has been loaded (http://vanderbiest.org/blog/2010/08/03/silverlight-4-childwindow-is-not-visible/)

No comments:

Post a Comment

14.2.12

Extension Methods for Null Objects

Is it possible to use an extension method on something that is null?

How beautiful would it be to do something like:
if (!MyString.IsNull()) return MyString.ToString();
I read somewhere a couple of years ago that would be impossible because if the object was null you’d not be allowed to call the method or something like that… But in my head it makes perfect sense.

So I have been refraining myself of doing this for a long time but today I felt brave enough.

The Method Extensions:
public static bool IsNull(this string str)
{
    return str == null;
}

public static string ToStringSafe(this object obj)
{
    return (obj ?? string.Empty).ToString();
}
The main method obviously every good test program should be a console application:
static void Main(string[] args)
{
    string str = null;

    if (str.IsNull())
        Console.WriteLine("It was null...");
    else
        Console.WriteLine("It wasn't null...");

    Console.WriteLine(str.ToStringSafe());

    Console.ReadKey();
}
And it works! This just opens a new dimension to my spaghetti recipes.

The first useful example that comes to my mind apart from the ToStringSafe and ToInt, ToDateTime... Look at me, I can't stop! is:

/// 
/// Disposes the object if it's not null.
/// 
public static void DisposeSafe(this IDisposable DisposableObject)
{
    if (DisposableObject != null)
        DisposableObject.Dispose();
}
With this method I won’t have to worry if the object is null or not. Everything is disposed properly!

It frightens me sometimes to get so excited about this things…

No comments:

Post a Comment

8.2.12

Shrink All the Databases

I wouldn’t recommend to do this in a production environment it doesn’t sounds to me too best practicy,  but if your development is running out of hard drive space I think this is a good alternative to shrinking the databases one by one…

The SQL script I use is this:

declare @db varchar(255)declare c cursor for
select name from sys.databases where is_read_only=0 and state=0
  and name not in ('master','model','tempdb','msdb')
open c
fetch c into @db
while @@fetch_status=0
begin
  exec SP_dboption @db,'trunc. log on chkpt.','true'
  DBCC shrinkdatabase (@db)
  fetch next from c into @db
end
close c
deallocate c
Shrink All The Databases

(I got it from here but mine is properly formatted :P)

No comments:

Post a Comment

2.2.12

Extending, Overriding and Base Classes

A couple of days ago my cousin asked me about the meaning of the word override. I tried to explain it with a couple of stupid examples and both sounded dull… Well this is a real life example.

We want to create Silverlight web parts and all of them share the same basic properties and the same render method. So extending Microsoft.SharePoint.WebPartPages.WebPart we will create a BaseSilverlightWebPart with this features (overriding the render method of the WebPart class) and then we will use it to create the other web parts easily.

The base class is like this:
    public abstract class BaseSilverlightWebpart : Microsoft.SharePoint.WebPartPages.WebPart
    {
        #region Web Part Properties
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Stratex")]
        [WebDisplayName("XAP List URL")]
        [Description("Select the URL of the XAP list.")]
        public string XAPListUrl { get; set; }
        #endregion

        #region Private Properties
        Dictionary<string, string> InitParams;
        #endregion

        #region Abstract
        /// <summary>
        /// Setup here the of the XAP you will use
        /// </summary>
        public abstract string XAPName { get; }

        /// <summary>
        /// Setup here the initial parameters you will use in your Silverlight Web Part
        /// </summary>
        public abstract void SetUpParameters();
        #endregion

        #region Methods
        public void AddParameter(string Name, string Value)
        {
            if (InitParams == null)
                InitParams = new Dictionary<string, string>();

            if (InitParams.ContainsKey(Name))
                InitParams[Name] = Value;
            else
                InitParams.Add(Name, Value);
        }
        #endregion

        #region Overrides
        protected override void CreateChildControls()
        {
            SetUpParameters();

            if (string.IsNullOrEmpty(XAPListUrl))
                XAPListUrl = string.Format("{0}/Lists/XAPLibrary/", SPContext.Current.Web.ServerRelativeUrl);

            //Sometimes when you create the web part it's 0px by 0px... ¬ ¬
            if (string.IsNullOrEmpty(Height)) Height = "150px";
            if (string.IsNullOrEmpty(Width)) Width = "150px";

            LiteralControl obj = new LiteralControl();
            obj.Text = "<object id='silverlightHost' height='" + Height + "' width='" + Width +
                @"' data='data:application/x-silverlight-2,' type='application/x-silverlight-2' style='display:block' class='ms-dlgDisable'>
                            <param name='Source' value='" + XAPListUrl + XAPName + @"' />
                            <param name='MinRuntimeVersion' value='3.0.40624.0' />
                            <param name='Background' value='#00FFFFFF' />
                            <param name='windowless' value='true' />
                            <param name='autoUpgrade' value='true' />
                            ";

            if (InitParams.Count > 0)
            {
                obj.Text +="<param name='initParams' value='";

                int i = 0;
                foreach (var param in InitParams)
                {
                    if (i++ == 0)
                        obj.Text += string.Format("{0}={1}", param.Key, param.Value);
                    else
                        obj.Text += string.Format(", {0}={1}", param.Key, param.Value);
                }

                obj.Text += @"' />
                ";
            }
            obj.Text += @"<a href='http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0' style='text-decoration: none;'>
                <img src='http://go.microsoft.com/fwlink/?LinkId=108181' alt='Click here to install Silverlight' style='border-style: none'/>
                </a>
                </object>";

            this.Controls.Add(obj);
        }
        #endregion
    }
Extending it we can create a Silverlight Web Part as easy as:
    public class DynamicStrategyMap : BaseSilverlightWebpart
    {
        #region Overrides
        public override string XAPName
        {
            get { return "StratexPointStrategyMap.xap"; }
        }

        public override void SetUpParameters()
        {
            AddParameter("site", HttpUtility.UrlEncode(SPContext.Current.Web.ServerRelativeUrl));
        }
        #endregion
    }
Note that wou dont have to override nothing if you don't need to. The render method is exactly the same as in the base class so we don't have to name it. The class will use its base class method automatically. Look how we are saving code not writing again all the properties or the big render method from the base class here, we just change what we really need to change.
We can also add new properties if we want as in:
    public class StratexHeartBeat : BaseSilverlightWebpart
    {
        #region WebPartProperties
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Stratex")]
        [WebDisplayName("NumberOfEvents")]
        public string NumberOfEvents { get; set; }

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Stratex")]
        [WebDisplayName("TimerLapse")]
        public string TimerLapse { get; set; }

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("Stratex")]
        [WebDisplayName("Indicator Summary Url")]
        public string IndicatorSummaryUrl { get; set; }
        #endregion

        #region Overrides

        public override string XAPName
        {
            get { return "StratexHeartBeat.xap"; }
        }

        public override void SetUpParameters()
        {
            AddParameter("site", HttpUtility.UrlEncode(SPContext.Current.Web.Url));

            if (string.IsNullOrEmpty(IndicatorSummaryUrl))
                IndicatorSummaryUrl = string.Format("{0}/Lists/WebPartPages/IndicatorSummary.aspx", SPContext.Current.Web.ServerRelativeUrl);

            AddParameter("indicatorsummaryurl", IndicatorSummaryUrl);

            if (Common.ConvertToInt(NumberOfEvents) < 1) NumberOfEvents = "1";

            AddParameter("numberofnews", NumberOfEvents);

            if (Common.ConvertToInt(TimerLapse) < 1) TimerLapse = "1";

            AddParameter("timerlapse", TimerLapse);
        }
        #endregion
    }
Or we can ever add more code to the render overriding the overrided render method.
    public class Commentary : BaseSilverlightWebpart
    {
        #region Overrides
        public override string XAPName
        {
            get { return "Commentary.xap"; }
        }

        public override void SetUpParameters()
        {
            AddParameter("site", HttpUtility.UrlEncode(SPContext.Current.Web.ServerRelativeUrl));
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            //We are using this code to be able to close the explorer window from Silverlight
            LiteralControl JavaScript = new LiteralControl();

            JavaScript.Text = @"<script type='text/javascript'>
                                function doCloseLocal() 
                                {
                                    var version = parseFloat(navigator.appVersion.split('MSIE')[1]);

                                    if (version >= 7) {window.open('', '_parent', ''); }

                                    else { window.opener = self;  }

                                    window.close();
                                }
                                </script>";
            this.Controls.Add(JavaScript);
        }

        #endregion
    }
Note that before adding the new control we call the base.Render so the web part is rendered in the page.
So this is how overriding looks like in real life. Now it make sense… or does it?

No comments:

Post a Comment

12.1.12

About Windows Phone 7 and SharePoint authentication

Connecting the phone to our SharePoint environment was my Christmas project, and it took me a while... In the end I managed to do it and I thought it could be a good idea to share the joy. Besides, I have read a lot of blogs about this matter all of them? and I want to add my contribution to it.

Let's go to the matter. I created a class called SPAuthBridge from the code in the SDK that can be used to set up the connections to the SharePoint server.
using System;
using System.IO;
using System.Net;
using System.Text;

namespace PhoneUtils.Code
{
    public class SPAuthBridge
    {
        #region Properties
        public CookieContainer cookieJar = new CookieContainer();

        string SiteUrl, User;
        string Password; //This should be securestring, but I don't think it's available in WP7
        #endregion

        #region Constructors
        public SPAuthBridge(string SiteUrl, string User, string Password)
        {
            this.SiteUrl = SiteUrl;
            this.User = User;
            this.Password = Password;
        }
        #endregion

        #region Public Methods
        public void Authenticate()
        {
            try
            {
                if (string.IsNullOrEmpty(SiteUrl)) throw new ArgumentOutOfRangeException("The SPAuthBridge was not properly initialized");

                System.Uri authServiceUri = new Uri(string.Format("{0}/_vti_bin/authentication.asmx", SiteUrl));

                HttpWebRequest spAuthReq = HttpWebRequest.Create(authServiceUri) as HttpWebRequest;
                spAuthReq.CookieContainer = cookieJar;
                spAuthReq.Headers["SOAPAction"] = "http://schemas.microsoft.com/sharepoint/soap/Login";
                spAuthReq.ContentType = "text/xml; charset=utf-8";
                spAuthReq.Method = "POST";

                //add the soap message to the request
                spAuthReq.BeginGetRequestStream(new AsyncCallback(spAuthReqCallBack), spAuthReq);
            }
            catch
            {
                TriggerOnAuthenticated(false);
            }
        }
        #endregion

        #region Private Methods
        private void spAuthReqCallBack(IAsyncResult asyncResult)
        {
            string envelope =
                    @"<?xml version=""1.0"" encoding=""utf-8""?>
                    <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
                      <soap:Body>
                        <Login xmlns=""http://schemas.microsoft.com/sharepoint/soap/"">
                          <username>{0}</username>
                          <password>{1}</password>
                        </Login>
                      </soap:Body>
                    </soap:Envelope>";

            UTF8Encoding encoding = new UTF8Encoding();
            HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
            Stream _body = request.EndGetRequestStream(asyncResult);
            envelope = string.Format(envelope, User, Password);
            byte[] formBytes = encoding.GetBytes(envelope);

            _body.Write(formBytes, 0, formBytes.Length);
            _body.Close();

            request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
        }

        private void ResponseCallback(IAsyncResult asyncResult)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);
                Stream content = response.GetResponseStream();

                if (request != null && response != null)
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        using (StreamReader reader = new StreamReader(content))
                        {
                            //Put debugging code here
                            string _responseString = reader.ReadToEnd();
                            reader.Close();
                        }
                    }
                }

                //authentication complete
                TriggerOnAuthenticated(true);
            }
            catch
            {
                TriggerOnAuthenticated(false);
            }
        }
        #endregion

        #region Events
        public delegate void OnAuthenticatedHandler(bool Success);

        public event OnAuthenticatedHandler OnAuthenticated;

        protected virtual void TriggerOnAuthenticated(bool Success)
        {
            if (OnAuthenticated != null)
                OnAuthenticated(Success);
        }
        #endregion
    }
}

The way to use this class is fairly simple, you create the SPAuthBridge object, you call the Authenticate method and you are ready to go, something like this:

        StratexWP7SoapClient StratexWP7 = new StratexWP7SoapClient(); //This is my web service
        SPAuthBridge SharePointAuth;

        public MainPage()
        {
            InitializeComponent();

            (...)

            SharePointAuth = new SPAuthBridge(SiteUrl, Username, Password);
            SharePointAuth.OnAuthenticated += new SPAuthBridge.OnAuthenticatedHandler(SharePointAuth_OnAuthenticated);

            if (!string.IsNullOrEmpty(Password))
                SharePointAuth.Authenticate();
            else
                MessageBox.Show("The application should be configured before use.");
        }

        void SharePointAuth_OnAuthenticated(bool Success)
        {
            if (!Success)
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                    { MessageBox.Show("There was an error on the authentication procedure. Please check the configuration."); });

                return;
            }

            StratexWP7.CookieContainer = SharePointAuth.cookieJar; //This is all you have to do to connect your web service. \m/ O.O \m/

            HookEvents();

            RequestData();
        }

It looks great when it works…

clip_image002clip_image002[4]
(By the way the charts are from AmCharts)

No comments:

Post a Comment

11.1.12

Scroll bars appear in SharePoint 2010 when rendering Silverlights (Part 2)

Yes, every time you fix the height or the width of the web part it shows those ugly scrollbars.

This is not the first time I go through this, but I think this time I have solved it for good or until we get the next version of SharePoint next year…. The problem was the way I was creating the Silverlight object I was using an inline CSS style. It looked a bit like:
<object id='silverlightHost' style='height: 600px; width: 350px; margin: 0; padding: 0;' data='data:application/x-silverlight-2,' type='application/x-silverlight-2'>

After a thousand try / error experiments don’t ever think I am capable of creating a SharePoint 2010 OOTB Silverlight Web Part and copying it I changed the first line of the object to:
<object id='silverlightHost' height='600px' width='350px' data='data:application/x-silverlight-2,' type='application/x-silverlight-2' style='display:block' class='ms-dlgDisable'>
And that does the trick.

No comments:

Post a Comment

6.1.12

Creating Events in Silverlight

I have read it’s impossible in a couple of places, i don’t know if it was in the previous versions, but at least since Silverlight 3 is possible… and even more… easy.

Here is an event I use to check when an item has moved.

        #region Events
        public delegate void PositionChangeHandler(Object Sender);

        public event PositionChangeHandler PositionChangedEvent;

        protected virtual void OnPositionChanged()
        {
            if (PositionChangedEvent != null)
                PositionChangedEvent(this);
        }
        #endregion

And then in the method where I am updating the position of the item:
OnPositionChanged();

After that we can easily hook to the event from the other classes:
ParentObjective.PositionChangedEvent += new Objective.PositionChangeHandler(RelatedObjectives_PositionChangedEvent);

Nice and easy.

No comments:

Post a Comment

4.1.12

Configuring Silverlight and Web Services with SSL and Self Signed Certificates

I had a SharePoint server working perfectly or at least as well as it works in HTTP, but suddenly I felt the urge to make it HTTPS. I extended the web application etc., and I was able to access everywhere, but Oh surprise!, my silverlights were not working.

I changed the <security mode="Transport" /> in the ServiceReferences.ClientConfig but I was always getting the infamous:
An error occurred while trying to make a request to URI 'https://MyURL/_vti_bin/Service.asmx'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute.
There were a couple things to fix here.

The first thing is to add a proper self signed certificate to your site.
C:\Program Files\Microsoft SDKs\Windows\v7.1>MakeCert.exe -r -pe -n "CN=MyURL" -sky exchange -ss my
The MyURL is very important. You can’t use any self signed certificate, you should use one that suits the URL of your site.
The certificate is stored in your personal certificates, so to export it you should execute MMC.exe, and there:
File –> Add/Remove Snap-In –> Certificates –> My user account –> Finish –> OK
Then you will be able to see your certificates. The one you just created is going to be at:
Certificates – Current User –> Personal –> Certificates –> MyURL
There you should do:
Right Click –> All Tasks –> Export
And there make sure you export the private key with the certificate. This will give you as a result a .pfx file.

Now we can go to the server we want to make SSL, if we were not there yet, and copy the .pfx file somewhere we are going to remember later.

Then we open the IIS Manager select the Home node and then click in the Server Certificates image.

On the right column you should click Import and then select the .pfx file you just created. After the import you should be able to see the new certificate on the Server Certificates list.

Then we will click on the 443 site collection node (Mine is called SharePoint – 443) there, again in the right column, select Bindings. Select Https (add a new one if you don’t have it) and click edit. On the SSL Certificate drop down list select the new certificate you just uploaded.

Well, we have done de hard part, now everything is easier.

Now we’ll add the crossdomain.xml and the clientaccesspolicy.xml files to both the 80 and the 443 folders. (c:\inetpub\…\443)
The content of this files is:

crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="*"/>
  <allow-http-request-headers-from domain="*" headers="SOAPAction"/>
</cross-domain-policy>

clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="http://*"/>
        <domain uri="https://*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

And now the even easier part. Configuring the browser.
We should navigate to https://MyURL and you will see something like this:
image

There you should continue to that web page (is recommended). And after that you’ll see URL bar turn red. Good.
Click on the Certificate Error button and then in the View certificates link:
image

After that click on:
Install Certificate… –> Next –> image & Next –> Finish –> Yes –> Ok.
Now close the browser and access again to your https://myurl. Now you should see the URL bar in white and the Lock Icon besides:
image

We are doing well. Now we’ll delete the cookies and everything else, why not?:
image

For the finishing touches we will reset the IIS and jump three times on one foot.

Now you should finally be able to connect to your SSL web services and to debug them from the Visual Studio.

No comments:

Post a Comment