adrian’s blog

September 23, 2008

Whoami in SharePoint

Filed under: Web — Tags: , , , — Adrian @ 9:25 pm

One of the nicest things in SharePoint is that you can access it not only through the web interface, but through its web services as well. Combining this with AJAX, you can build pretty good user interfaces with a SharePoint backend.
When doing this you’ll definitely be interested in knowing who is currently logged in.
So if you are modifying a SharePoint generated page (like NewForm.aspx, EditForm.aspx or a page associated with a view) and add (D)HTML code to it, you can easily access the _spUserId variable which holds the current logged in user ID in SharePoint.
From this point on if you’re interested in more details you just simply run a query against the user list using SharePoint web services.
If you want to have these information in a page of your own, you can simply run that query using the CAML tag UserID.

<Query>
  <Where>
    <Eq>
      <FieldRef Name="ID"/>
      <Value Type="Integer"><UserID Type="Integer"/></Value>
    </Eq>
  </Where>
</Query<

Just as a note, don’t forget to put Type="Integer" in there.

If you wonder how I got over this, you should read my other article.

Discover CAML by examples

Filed under: Software, Web — Tags: — Adrian @ 6:53 pm

CAML is the SQL of SharePoint. If you will access SharePoint through its web services you will definately need to be familiar to a certain degree with CAML. You can read the documentation from MSDN, but I will tell you how to learn it through examples. And actually to create your own examples.
There are a few CAML builders out there, but if you know how to use SharePoint, you have a basic one hidden in there.
Let’s take it step by step.

  1. Go to your SharePoint
  2. Create a list
  3. Create a view for the list (for the sake of simplicity let’s name it My View)
  4. Choose the conditions that you’re interested in for the query, let’s say all the items modified today, and save the view.
    View filter in SharePoint

    View filter in SharePoint

  5. Go to the list settings and save the list as a template
    Save list as template in SharePoint

    Save list as template in SharePoint


    List template is saved

    List template is saved

  6. Go to the template list library
    List template gallery

    List template gallery

  7. Download the template
  8. The template is actually a zip file. Rename it from mylist.stp to mylist.zip and extract the manifest.xml file from it.
  9. Now open the XML file (with FireFox) and go to the element /ListTemplate/UserLists/List/Metadata/Views/View[@DisplayName = 'My View'](the first /ListTemplate/UserLists/List/Metadata/Views/View for which the attribute DisplayName is My View). Under this element you will find a Query element. This is what you need, your CAML query.

And that manifest.xml file is also the source of some other useful stuff like the internal name of the fields (the StaticName attribute of the /ListTemplate/UserLists/List/Metadata/Fields/Field elements).

September 20, 2008

JavaScript: keys vs properties

Filed under: Web — Tags: , — Adrian @ 5:47 pm

Maybe some of you are familiar with the concept of map from Java or .Net. What about JavaScript? Do you something similar to this? Almost.
Every object in JavaScript has a set of properties, that can you can access through the [] operator. So, to get a property value: object[propertyName] and to set it: object[propertyName] = propertyValue. And yes, this works for every object ;) .
But why almost? Why not exactly like in Java or .Net?
Well, in Java (or .Net) the map is actually a set of pairs (key, value), opposed to JavaScript, where an object has a set of pairs (name, value). You can see that in one case I used key and in the other I used name. Because in Java any object can be a key and in JavaScript only String’s can be.
Confused? Let’s try some examples.
First, let’s create an object and rewrite its toString method:

var key = new Object();
key.toString = function() {
    return "abc";
}

So now alert(a) will actually display “abc”.
And now let’s create another object that we will use it to test the properties on it.

var obj = new Object();
obj["abc"] = 1;
obj[key] = 2;
obj[1] = 3;
obj["1"] = 4;

Probably you’ll be surprised to find out that obj["abc"] returns 2. And this is because the object is first converted to string and then used as the property name. Same for obj[1].
More surprisingly is that this is the case for arrays:

var arr = new Array();
arr["1"] = 4;

Now arr[1] will return 4 and arr.length will return 2, even tough the initial array length was 0.
If you check out the ECMAScript standard, everything is as should be, but still not very intuitive. In my opinion :) .

September 16, 2008

Web progress bar

Filed under: Web — Tags: , , , , , — Adrian @ 9:05 am

Would you like something like this in your web page?
web progress bar
Then I will show you how to do it.
The basic idea is pretty simple: implement it using 3 DIVs – one for the progress bar background, one for the completed part and one for the label (indicating the completed value or percent). They are stacked on top of each other in the specified order, from bottom to top.

We will have a main DIV, the actual progress bar, and inside it a completed one that will take as much space from its parent as the task is completed and a label to indicate that percentage.

On the main DIV we specify a border that will enclose the entire progress bar and a background that will indicate the remaining part. We also specify a different background on the completed DIV to indicate the completed part of the task. As for the label we specify only a font color and the background should remain transparent, so the label just sits on the progress bar.

Both children DIVs of the progress bar are floated to left and the label one has a negative margin to allow to be displayed at the same coordinates as the completed one.

  • HTML code

    <div id='progressbar' class='progressbar'>
        <div id='completed' class='completed'></div>
        <div id='label' class='label'>0%</div>
    </div>
    

  • CSS

    .progressbar {
        /* only for better layout :)  */
        background-color: white;
        border: solid 1px black;
        width: 100px;
        height: 10px;
        font-family: arial;
        font-size: 10px;
    }
    
    .progressbar .completed {
        /* mandatory */
        width: 0%;
        height: 100%;
        z-index: 1;
        float: left;
    
        /* only for better layout :)  */
        background-color: navy;
    }
    
    .label {
        /* mandatory */
        width: 100%;
        height: 100%;
        z-index: 2;
        float: left;
    
        /* only for better layout :)  */
        text-align: center;
        vertical-align: middle;
        color: yellow;
    }
    

    As you can see some of the CSS properties are mandatory for the component to render as a progress bar, as some of the properties are used only for a visually appealing layout.

  • JavaScript

    function setPercent(percent) {
        document.getElementById("label").innerHTML = percent + "%";
        document.getElementById("label").style.marginLeft = "-" + percent + "%";
        document.getElementById("completed").style.width = percent + "%";
    }
    

Next step will be to wrap all these into a nice component (JavaScript class). But this depends only on your architectural skills, as now you have the basic technique.

And in the end you can see a full working example, tested on IE6, FF3 and Safari 3. If you get rid of the hassle of implementing this yourself and you want a ready to use and easy to integrate progress bar component for your web pages you should see the MyUI JavaScript library. A demo is also available.

Just a side note, a throbber (or indeterminate progress bar) is easier to implement, that one being only a simple animated image.

September 12, 2008

Cross browser XMLHttpRequest

Filed under: Web — Tags: , , — Adrian @ 12:08 am

AJAX has become more and more widely used. It is a cool thing, you can do a lot with it, but basically (and here is the best part) it is only a new JavaScript object: XMLHttpRequest. There is no need to learn new technologies or languages.
Unfortunately, not all the browsers (please read especially IE) support this in a native and smooth way. If in FF2+ and even IE7, this comes in a native way, in IE6 this comes only as an ActiveX object.
The good news is that, except how the objects are instantiated, everything else is the same.
As I said in FF/Mozilla this comes in a native smooth way


var xmlHttp = new XMLHttpRequest();

but in IE5 and 6, to create it, you actually create an ActiveX object


var xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");

And that’s not all, even the ActiveX object class can be different from Windows version to another, so you might also have:


xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

So every time you want AJAX you might end up with something like this:

    var xmlHttp;
    // use the ActiveX control for IE5.x and IE6
    try {
        xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
    } catch (othermicrosoft){
        try {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (native) {
            // If IE7, Mozilla, Safari, etc: Use native object
            xmlHttp = new XMLHttpRequest();
        }
    }

As I’m lazy and I don’t want to write this code every time, I decided to wrap it up in a nice cross browser way.

How? Look at the code below.

try {
    // test to see if XMLHttpRequest is defined
    XMLHttpRequest.DONE;
}
catch (e) {
    XMLHttpRequest = new Object();
    // define also all the constants
    XMLHttpRequest.UNSENT = 0;
    XMLHttpRequest.OPENED = 1;
    XMLHttpRequest.HEADERS_RECEIVED = 2;
    XMLHttpRequest.LOADING = 3;
    XMLHttpRequest.DONE = 4;
}

/** Creates new instance of the XMLHttpRequest object */
XMLHttpRequest.newInstance = function() {
    var xmlHttp = null;
    // use the ActiveX control for IE5.x and IE6
    try {
        xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
    } catch (othermicrosoft){
        try {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (native) {
            // If IE7, Mozilla, Safari, etc: Use native object
            xmlHttp = new XMLHttpRequest();
        }
    } 

    return xmlHttp;
};

Just to explain a little bit what happens. First we test if the XMLHttpRequest exists, by calling a property on it. If it doesn’t exist, then this will raise an exception and then we will create it. After this, the next step will be to define a method (similar to a static one) to create a new instance and enclose the entire cross browser code. So now we will create a new XMLHttpRequest like this:


var xmlHttp = XMLHttpRequest.newInstance();

Lazy enough for you !? ;)

September 4, 2008

Mobile device filter in ASP.net

Filed under: Software, Web — Tags: , , — Adrian @ 9:37 pm

The mobile web is increasing rapidly. Creating different web sites for mobile users is not a solution, rather having the same content, but customized through CSS for different browsers and devices. But this article will not focus on this part, but rather on what is before: recognizing the browser/device of the user so you can choose the right CSS file(s).

For recognizing the devices we will use WURFL, on open source database containing device capabilities. I will also not cover here the mobile device recognition topic.

What I will describe, will be an HTTP filter for pages that will try to recognize the mobile device and store it in the context items for future use. Of course you can add your own custom tasks to it (e.g. redirect to another page if a page is not available for mobile devices or select automatically the right CSS).

The filter is implemented as an HTTP module that is executed before the actual request is processed. Then it matches the User Agent string against the WURFL database for getting the device id. Because some mobile providers are rewriting the User Agent and putting the information into the X-Device-User-Agent HTTP header we will also look into that one as well. (Later edit) And just to be sure that you also recognize Opera Mini (and actually the real device) you can inspect the information in the X-OperaMini-Phone-UA header. As a consequence the filter will use a list of headers.

And now the code:

public class WURFLFilter : IHttpModule
{
    ///
    /// The HTTP headers inspected for the User Agent string. The headers are inspected in this order.
    /// User-Agent - the standard header containing the user agent string
    /// x-device-user-agent - some mobile providers overwrite the User Agent,
    ///     but they put the real user agent in this header
    /// X-OperaMini-Phone-UA - Opera mini overwrites the standard header,
    ///     but moves the information in this header
    ///
    private static String[] UA_HEADERS = new String[]
                { "HTTP_USER_AGENT", "X-DEVICE-USER-AGENT", "HTTP_X_OPERAMINI_PHONE_UA" };

    private HttpApplication httpApp;
    private deviceFileProcessor wurfl
    {
        get
        {
            // get the WURFL processor from cache or load it from file
            deviceFileProcessor d = (deviceFileProcessor)httpApp.Context.Cache["wurfl"];
            if (d == null)
            {
                String wurflPath = httpApp.Server.MapPath(ConfigurationSettings.AppSettings["wurfl.path"]);
                d = new deviceFileProcessor(wurflPath);
                httpApp.Context.Cache.Insert("wurfl", d, new CacheDependency(wurflPath));
            }
            return d;
        }
    }

    public void Init(HttpApplication httpApp)
    {
        this.httpApp = httpApp;
        httpApp.PostAcquireRequestState += new EventHandler(OnRequest);
    }

    void OnRequest(object sender, EventArgs a)
    {
        HttpContext context = ((HttpApplication)sender).Context;
        String mobileDeviceId = null;
        Hashtable userAgents = wurfl.getsdUserAgentAndId;

        for (var i = 0; i < UA_HEADERS.Length; i++)
        {
            String ua = context.Request.Headers[UA_HEADERS[i]];
            mobileDeviceId = (String)(String.IsNullOrEmpty(ua) ? null : userAgents[ua]);
            if (mobileDeviceId != null)
                break;
        }

        context.Items.Add("mobileDeviceId", mobileDeviceId);
    }

    public void Dispose()
    {
    }

}

Some improvements can be made, like caching the mobileDeviceId into the session (we suppose that you cannot change your device during the session :) ). You probably noticed that I cached the WURFL file processor (the WURFL data file is quite big and it doesn’t make sense to read it every time). The cache dependency is made on the WURFL data file (the path is stored into application settings under the wurfl.path key) so you can update the file without any worries.

XSLT handler in ASP.net

Filed under: Software, Web — Tags: , , , — Adrian @ 9:42 am

Next I will explain you a solution that may come handy to you. First of all, the problem. Quite simple: you have some HTML pages, that you would like to include them in your pages, but in a different format/layout. Unfortunately you cannot modify the pages as you’re not the author. Just to understand better, let’s say that you want to include some Wikipedia articles in your pages. But they have to match with your own layout and you want only some sections of them.
So you have to transform an HTML into another. This sounds pretty much like XSLT and this is what we will use. It will be your task to write the XSLT. I’m only going to tell you how to integrate in your web application.

For the sake of simplicity and reuse, we will write an ASP.net handler for XSLT file that it will take the XSLT file and receive as a parameter the XML/HTML/XHTML URL and it will output the transformed result.

Find below the code for it:

public class XSLTHandler : IHttpHandler
{
    // process the request
    public void ProcessRequest(HttpContext context)
    {
        // the XSLT argument list
        XsltArgumentList xslArg = new XsltArgumentList();

        String url = context.Request.QueryString.Get("u");
        // if no URL, either special or from u parameter then send a NOT_FOUND error
        if (url == null)
        {
            send(context.Response, HttpStatusCode.NotFound);
            return;
        }

        // adding the URL as an XSLT parameter
        xslArg.AddParam("url", "",  url);

        try
        {
            // load the XML document at the specified URL
            XmlDocument xmlDoc = loadXMLDocument(url,
                    "POST".Equals(context.Request.HttpMethod)
                    ? context.Request.Form.ToString() : null);

            // load xsl
            String xslPath = context.Request.MapPath(context.Request.Url.LocalPath);

            // try to get the compiled XSLT from cache
            XslCompiledTransform xslTransform = (XslCompiledTransform)context.Cache.Get(xslPath);
            if (xslTransform == null)
            {
                // if the XSLT file doesn't exist, send a 404
                if (!File.Exists(xslPath))
                {
                    send(context.Response, HttpStatusCode.NotFound);
                    return;
                }

                xslTransform.Load(xslPath);

                // put the XSLT into cache
                context.Cache.Insert(xslPath, xslTransform, new CacheDependency(xslPath));
            }

            // transform
            context.Response.ContentType = "text/html";
            context.Response.Clear();
            xslTransform.Transform(xmlDoc, xslArg, context.Response.Output);

        }
        catch (HttpException exc)
        {
            if (exc.GetHttpCode() == (int) HttpStatusCode.Redirect)
            {
                // if it is to be redirected, redirect to the url
                context.Response.Redirect(url);
            }
            else
            {
                // if any other error, then send the error code
                send(context.Response, (HttpStatusCode)exc.GetHttpCode());
            }
        }
        catch (Exception)
        {
            // if other error send an internal server error response
            send(context.Response, HttpStatusCode.InternalServerError);
        }
    }

    // IHttpHandler method
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    private void send(HttpResponse Response, HttpStatusCode StatusCode)
    {
        Response.Clear();
        Response.StatusCode = (int)StatusCode;
        Response.StatusDescription = StatusCode.ToString();
        Response.End();
    }

    ///
    /// Load and returns an XML document from the given url.
    ///
    /// the url where is the XML content
    /// if not null the request will be a POST request
    /// and the parameters are sent along with the request; if null then the request method is GET
    /// the loaded XML document
    public static XmlDocument loadXMLDocument(String url, String postParams)
    {
        Object reader;
        if (url.StartsWith("/") || (!url.Contains(Uri.SchemeDelimiter)))
        {
            // if it is a local request then use the internal execute instead of making a web request
            // also the form and query string parameters are preserved
            StringWriter writer = new StringWriter();
            HttpContext.Current.Server.Execute(url, writer, true);
            reader = new StringReader(writer.ToString());
        }
        else
        {
            // create webrequest
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Timeout = RequestTimeout;
            // you can also add a proxy
            //request.Proxy = WebProxy;
            if (postParameters != null)
            {
                // Set values for the request back
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = postParameters.Length;

                // Write the request
                StreamWriter stOut = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
                stOut.Write(postParameters);
                stOut.Close();
            }

            // get the response of the request
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // if something went wrong don't try to parse the document
            if (response.StatusCode != HttpStatusCode.OK)
                throw new HttpException((int)response.StatusCode, response.StatusDescription);

            if (response.ContentType.StartsWith("text/html"))
            {
                // if it is HTML transform it with SgmlReader
                // create instance of SGMLReader and change settings
                SgmlReader sgmlReader = new SgmlReader();
                sgmlReader.WebProxy = Configuration.Proxy;
                sgmlReader.DocType = "HTML";
                sgmlReader.CaseFolding = CaseFolding.ToLower;
                sgmlReader.InputStream = new StreamReader(response.GetResponseStream(), Encoding.UTF8, true);

                reader = sgmlReader;
            }
            else if (response.ContentType.StartsWith("text/xml"))
            {
                // if not html simply get it from the response
                reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8, true);
            }
            else
            {
                // redirect to the normal page, as it is nor HTML nor XML
                throw new HttpException((int)HttpStatusCode.Redirect, url);
            }
        }
        // load the XML document
        XmlDocument xmlDoc = new XmlDocument();
        if (reader is TextReader)
            xmlDoc.Load((TextReader)reader);
        else if (reader is XmlReader)
            xmlDoc.Load((XmlReader)reader);
        return xmlDoc;
    }
}

To explain shortly what happens: when a file like t.xslt is requested, the XSLTHandler will process the request. First it will load and compile the XSLT file using XSLTCompiledTransform, trying first to load the XSLT compiled object from cache.
Next step is to retrieve the XML/XHTML/HTML content from the URL given as the url parameter. If the content is HTML, then it will be transformed using an SGML parser into XHTML, so it can be transformed with XSLT. Then the actual processing takes place and the result is generated into the response output.

Of course the above code can be extended. You can put in the app configuration if you want to use the cache, what proxy to use, if you want to allow only URLs from some hosts to be parsed and so on. Also other parameters can be added as XSLT arguments: the URL of the XSLT file, the HTTP headers, the request parameters etc.

You saw in the code references to an SgmlReader and I also told you above about feeding the HTML content first into an SGML parser. But how to do it? The SgmlReader is already implemented and you can download it from here and use it like an XmlReader.

Last step is to configure the handler into the Web.config, by simply adding the handler to process *.xsl files:

    <httpHandlers>
        <add verb="*" path="*.xsl" type="XSLTHandler" />
    </httpHandlers>

That’s it!

Blog at WordPress.com.