June 2008 - Posts

Microsoft Technology Interoperability Improvements for PHP

 

When I got back from the MVP Interoperability Workshop last week (http://dotnet.org.za/willy/archive/2008/06/07/interoperability-highlight-t-3-days.aspx) I got buried in work that has been waiting for me and haven't had a chance to put up my post event info, so, finally here it is.

Way back in the days, first content management systems I dealt with were PHP based, like PHP-Nuke PostNuke, MyPHPNuke... etc, and this is basically where I fell in love with content management systems. They were modular, rich with features, stable most of the time, with great support from a large community, enjoying the power of peer review, and above all....... they were free!!

You had everything in one place -> news syndication, content management, collaboration, bulletin boards as well full blown e-commerce solutions. Most people have used these as platforms for successful web content management and e-commerce, even introducing their own touches by either using various components developed by others or developing the same themselves, so much so that winning combinations became a good solution concept that ended up being sold to others who wanted the same (besides just making money through e-commerce and advertising).

Today's unofficial statistics indicate trends where that PHP based sites constitute a considerable majority when it comes to e-commerce and web content management internet facing sites, where .NET and Java sit quite a bit behind.

Challenges with maintaining these PHP websites come when it comes to support of the underlying infrastructure and technology. PHP websites usually sit on Open Source platforms that require skills that are usually scarce and quite expensive as such. Linux distributions are usually hailed as secure and stable but they are not proper enterprise server platforms, SUSE was very close to being that, but eventually Novell just gave up on it (as most of you know).

This is where Microsoft can help, from Windows Server Platform that can provide proper scalability, and availability, to using new IIS7 (or IIS6) with FastCGI and SQL 2005 as a proper Enterprise Database solution (as opposed to MySQL) with variety of powerful features for PHP developers as well availability through either clustering or mirroring (far less complexity then clustering)  as well as scalability advancements that include table partitioning, replication enhancements, and 64-bit support.

I was truly inspired to do this session by Joe Stagner who's actually a PHP developer working for Microsoft who calls himself Misfit Geek, check out his blog on http://www.misfitgeek.com/.

In fact he was doing a session at TechEd US 2008 called PHP on Windows: Not an Oxymoron which is pretty much on the similar topic (http://www.misfitgeek.com/TechEd+2008+My+Presentations+Come+Say+Hello.aspx).

In the session we discussed interoperability of various Microsoft technologies with PHP.

We discussed what the differences between PHP and ASP.NET are, and main focus was on what .NET platform and Windows has that PHP can greatly benefit from.

What followed was the demo on configuring FastCGI on IIS and deploying PHP sites on it. Some of you might ask, but why, when I could run PHP on older version of CGI on IIS? Well older versions of CGI would work simply by starting up a new process every time a request would come and then after a web response was delivered it would close that process, albeit this would work, you could hardly call it efficient, and it would usually create quite a bit of overhead, with FastCGI once the process is started it can satisfy multiple requests.

Then there was also a demo on compiling PHP code in Visual Studio 2008 with project Phalanger (http://www.codeplex.com/Phalanger) which also features creating Silverlight projects for PHP. Then there was a demo on how you can use various powerful PHP libraries with C# in Visual Studio 2008 (Exif, Ming and Zlib), and then we took the PHP code that we compiled earlier and we AJAX-ed it with AJAX.NET (http://www.codeplex.com/phpmsajax).

Then we talked about the new CTP release of SQL Server driver for PHP (http://msdn.microsoft.com/en-us/data/cc299381.aspx) and how and why you should use it (check also http://blogs.msdn.com/sqlphp/ for more info). We also discussed PHP interoperability with COM and various interoperability options via Web Services.

Basically my goal was to show that there is no reason to choose either Microsoft or Open Source, but rather pick the best from both sides and get the best of both worlds.

The session was great, even more so as I got really good feedback from both PHP and .NET developers in the audience.

 You can download the presentation here: http://dotnet.org.za/blogs/zlatan/PHP%20Zlatan.zip

Google officially enters the South African Market (Public and Private Sector) with their first SA Partner Company - Faritec

If you haven't watched the announcement on the TV this morning made by the Faritec's person in charge of the new Google Enterprise division this morning you can read the news here:

http://www.fin24.com/articles/default/display_article.aspx?ArticleId=1518-24_2343140

Faritec are the first Google Partner, but I suspect not the last. Google have come to the South African market offering above all their Enterprise Search (scaled down Google internet search with Federated search and option of using some fancy 3D add-ons) offering to corporate and government clients in direct competition to Microsoft Enterprise Search and various other Enterprise Search offerings.

Also bear in mind that Microsoft Enterprise Search is a very powerful Search offering based on Microsoft Live search engine (those of you that attended my Enterprise Search lecture at the UCS conference in Johannesburg last year might remember -> Search in Microsoft Office SharePoint Server 2007: Customizing and Extending) and Microsoft has further bolstered their Enterprise Search offering by purchasing FAST, a Norwegian leading provider of enterprise search solutions for approx 1.2 billion US $ (http://www.microsoft.com/presspass/press/2008/jan08/01-08FastSearchPR.mspx).

This is going to be very interesting to see as Faritec is also one of leading Microsoft Gold Partners and Enterprise Search usually goes hand in hand with Enterprise Content Management solutions (like SharePoint). Isn't Faritec going to get in trouble with Microsoft for this?

Are we going to see SharePoint deployed with Google Enterprise Search? I'm asking this question because I would really like to see how that would work.

Also remember that Google has Google Sites (http://sites.google.com/, check out the Google Apps Premier Edition http://www.google.com/a/help/intl/en/admins/editions.html) which is threatening to become a serious competitor to SharePoint in future.

It looks like a serious clash of the Titans might happen here although Microsoft has managed to peacefully coexist with other ECM Titans on the SA Market (like EMC Documentum, OpenText Livelink and Hummingbird, IBM Filenet and others), but as we all know, it's not in Google's nature to be at peace with Microsoft. Let's see what happens.

Posted by Zlatan | 2 comment(s)
Filed under: , ,

Multiple RSS Aggregator Web Part Example

Ok so............. long time ago, in a city far far away (from Cape Town) our very own Willy (http://dotnet.org.za/willy) wanted to re-launch SAArchitect (http://www.saarchitect.net/) community and envisaged a need to aggregate all the feeds from SAArchitect community members and filter on a certain tag in the blog posts posted by those same members (in particular "SAArchitect" tag).  Since http://www.saarchitect.net/ is running on a SharePoint 2007 platform, he needed a SharePoint kind of guy that can make this idea a reality. He searched high and low, and after being bounced around a bit he found me :), and considering the fact that at that time I thought I might have some free time between 3am and 4am every 4th day I thought, why the hell not. So Willy even blogged about it to make sure that my commitment stayed public (http://dotnet.org.za/willy/archive/2008/02/20/sa-architect-re-launching-the-community-why-how-and-where-next.aspx).

I wrote the Web Part and sent it to Willy, and although he successfully tested it, he still didn't get around to deploying it (hosting company issues I think).

After all this time I decided to share this with the community, as this is quite cool for community sites powered by SharePoint 2007, and I'm sure someone else might also find it quite useful.

I needed first to know how to get a simple, single RSS feed to display its data so I found this example from Sahil (http://blah.winsmarts.com/2006-7-Sharepoint_Webparts_AS_-_Writing_the_WebParts_-_The_RSS_Feed_WebPart.aspx) and used it as a starting point.

The way this works is that you can specify multiple feeds (separated by a character ";"), and the filter criteria as well the number of feeds displayed. This was my first shot at it, and it's quite simple, so feel free to take it apart, and I think this concept has quite a bit of potential so I think I'll revisit this once again (when I find time) with even more exciting technology.

Be careful as the example uses "saarchitect" as default value to filter on, make sure to change that when you deploy the web part, or you can even take out that whole concept out of the code.

It was written with Visual Studio 2005 SP1 with VSeWSS 1.1 (beta I think).

You can download the project files + source code with a wsp here (http://dotnet.org.za/blogs/zlatan/RSSWebPart.zip).

It used standard references (Microsoft.SharePoint, System, System.Web, System.XML)

Here's the code:

 using System;

using System.Runtime.InteropServices;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Serialization;

 

using Microsoft.SharePoint;

using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.WebPartPages;

using System.Collections.Generic;

using System.Xml;

using System.Text.RegularExpressions;

using System.ComponentModel;

 

namespace RSSWebPart

{

    [Guid("c4cc9fd1-2865-4d28-9e33-6e2f80eb4868")]

    public class RSSWebPart : System.Web.UI.WebControls.WebParts.WebPart

    {

        public RSSWebPart()

        {

            this.ExportMode = WebPartExportMode.All;

        }

        private string rssUrl;

        private string feedName;

        private const string constDefFeedCriteriaValue = "saarchitect";

        private string filterCriteria = constDefFeedCriteriaValue;

        private const string constDefFeedLimitValue = "5";

        private string feedLimit = constDefFeedLimitValue;

        private int feedLmt;

        private string tagValue;

 

 

        protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)

        {

            try

            {

                feedLmt = Convert.ToInt32(feedLimit);

            }

            catch (Exception)

            {

                feedLmt = 0;

            }

            RssFeed feed = new RssFeed(rssUrl);

            feed.Sort(delegate(RssItem r1, RssItem r2)

            {

                return r2.PubDate.CompareTo(r1.PubDate);

            });

 

            int i = 0;

           

            foreach (RssItem singleRssItem in feed)

            {

                if (i < feedLmt)

                {

                    if (filterCriteria != null && singleRssItem.Tags != null)

                    {

                        tagValue = singleRssItem.Tags.ToLower();

                        if (tagValue.Contains(filterCriteria) == true)

                        {

                            writer.Write("<div class=\"container\">");

                            writer.Write("<font size=\"4\" face=\"Verdana\"><b><a href =\"");

                            writer.Write(singleRssItem.Href);

                            writer.Write("\"><font size=\"2\" face=\"Verdana\">");

                            writer.Write(singleRssItem.Title);

                            writer.Write("</a></b></font>");

 

                            writer.Write("<div class=\"module-content\"><table width=\"100%\" border=\"0\"><tr><td><font size=\"2\" face=\"Verdana\">");

                            writer.Write(singleRssItem.Body);

                            writer.Write("</font></td></tr></table></div>");

                            writer.Write("</div>");

 

                            writer.Write("<div class=\"module-content\"><table width=\"100%\" border=\"0\"><tr><td><font size=\"2\" face=\"Verdana\">");

                            writer.Write(singleRssItem.Tags);

                            writer.Write("</font></td></tr></table></div>");

                            writer.Write("</div>");

 

                            writer.Write("<div class=\"module-content\"><table width=\"100%\" border=\"0\"><tr><td><font size=\"2\" face=\"Verdana\">");

                            writer.Write(singleRssItem.PubDate.ToString());

                            writer.Write("</font></td></tr></table></div>");

                            writer.Write("</div>");

                            i++;

                        }

                    }

                }

            }

        }

 

        public string FeedName

        {

            get

            {

                return feedName;

            }

            set

            {

                feedName = value;

            }

        }

 

 

        [WebBrowsable(true),

        Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("URLs of the Feed"),

        WebDisplayName("URLs of the Feed"),

        Description("Please enter the URLs of the feed separated by ';' character.")]

        public string FeedURL

        {

            get

            {

                return rssUrl;

            }

            set

            {

                rssUrl = value;

            }

        }

 

        [WebBrowsable(true),

        Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("Filter Criteria"),

        WebDisplayName("Filter Criteria"),

        Description("Please enter the tag value you wish to filter on for desired RSS feeds."),

        DefaultValue(constDefFeedCriteriaValue)]

        public string FilterOn

        {

            get

            {

                return filterCriteria.ToLower();

            }

            set

            {

                filterCriteria = value.ToLower();

            }

        }

 

        [WebBrowsable(true)]

        [Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("Feed Limit"),

        WebDisplayName("Feed Limit"),

        Description("Defines the list the web part will read from."),

        DefaultValue(constDefFeedLimitValue)]

        public string FeedLimit

        {

            get

            {

                return feedLimit;

            }

            set

            {

                feedLimit = value;

            }

        }

 

    }

 

 

    internal class RssFeed : List<RssItem>

    {

        private XmlDocument rssDoc;

 

        internal RssFeed(string RssURL)

        {

 

            if (RssURL == null)

            {

                this.Add(new RssItem());

            }

            else

            {

                string[] rssUrlsArray = RssURL.Split(new char[] { ';' });

                foreach (string url in rssUrlsArray)

                {

                   

                    try

                    {

                        rssDoc = new XmlDocument();

                        XmlTextReader xRead = new XmlTextReader(url);

                        rssDoc.Load(xRead);

 

                        XmlNodeList xNodes = rssDoc.SelectNodes("./rss/channel/item");

                       

                        foreach (XmlNode xNode in xNodes)

                        {

                            

                            this.Add(new RssItem(xNode));

                           

                        }

                       

                    }

                    catch (Exception)

                    {

                        this.Add(new RssItem());

                    }

                }

            }

        }

    }

 

    internal class RssItem

    {

        private string title;

        private string href;

        private string body;

        private string tags;

        private DateTime pubDate;

 

 

        public string Href

        {

            get { return href; }

        }

 

 

        public string Title

        {

            get { return title; }

        }

 

        internal RssItem()

        {

            title = "Feed not available at this time";

            href = "~";

        }

 

 

        public string Body

        {

            get { return body; }

            set { body = value; }

        }

 

        public string Tags

        {

            get { return tags; }

            set { tags = value; }

        }

 

        public DateTime PubDate

        {

            get { return pubDate; }

            set { pubDate = value; }

        }

 

        internal RssItem(XmlNode xNode)

        {

            title = xNode.SelectSingleNode("./title").InnerText;

            href = xNode.SelectSingleNode("./link").InnerText;

            body = FixDesc(xNode.SelectSingleNode("./description").InnerText, href);

            pubDate = Convert.ToDateTime(xNode.SelectSingleNode("./pubDate").InnerText);

 

            XmlNodeList nodeList = xNode.SelectNodes("./category");

            foreach (XmlNode node in nodeList)

            {

                tags = tags + " " + node.InnerText;

            }

        }

 

        public string FixDesc(object desc, object link)

        {

            if (link == null || desc == null) return String.Empty;

 

            string description = desc.ToString();

            //Replace all HTML tags so none get cut-off and screw up the page

            Regex reg = new Regex("<.*?>", RegexOptions.Compiled);

            string stripDesc = reg.Replace(description, String.Empty);

            if (stripDesc.Length > 250)

            {

                int startPos = 250;

                char[] chars = stripDesc.ToCharArray();

                char c = chars[startPos];

                while (!Char.IsWhiteSpace(c) && startPos < chars.Length)

                {

                    startPos++;

                    c = chars[startPos];

                }

                stripDesc = new String(chars, 0, startPos) + " ... <a href='" + link.ToString() + "'> More</a>";

 

            }

            return stripDesc;

        }

    }

}

How to use Web Part Custom Properties in SharePoint 2007 and WSS 3.0

It's so weird how so many people ask you the same thing around the same time sometimes, anyway I've had some request around on how to create custom properties for Web Parts in SharePoint, more to the point, on how to get them to categorise and appear in the "Modify Web Part" panel.

It's quite simple actually, just declare the properties and decorate them with attributes like in the following example:

        [WebBrowsable(true),

        Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("URLs of the Feed"),

        WebDisplayName("URLs of the Feed"),

        Description("Please enter the URLs of the feed separated by ';' character.")]

        public string FeedURL

        {

            get

            {

                return rssUrl;

            }

            set

            {

                rssUrl = value;

            }

        }

 

Please note that Category attribute will basically create section for all your properties that carry that attribute value and WebDisplayName will be the name of the property appearing on the panel.

Visual Studio 2008 Extensions for Windows SharePoint Services have been released

Yes.... that's right, the long awaited extensions that give you among other things much needed SharePoint Web Part templates, have been released. Now you can add items into your SharePoint projects like Web Parts, Event Handlers, Definitions, Custom Fields etc.

Cool hey?

Well I think so......

Download it here:

http://www.microsoft.com/downloads/details.aspx?FamilyID=7bf65b28-06e2-4e87-9bad-086e32185e68&displaylang=en

Also check out the new http://www.mssharepointdeveloper.com/ for even more SharePoint Developer resources (very slick presentation too). Very smart from Microsoft to put all the SharePoint Development resources in one place.

Huge Security Flow in Ubuntu and Debian distributions

Hah can you believe it, I actually wanted to blog about this last week when I received the news from my friend and colleague Alistair, but due to my schedule I haven't had a chance.

Huge Hole in Open Source Software Found, Leaves Millions Vulnerable (http://www.dailytech.com/Huge+Hole+in+Open+Source+Software+Found+Leaves+Millions+Vulnerable/article11869.htm)

You'll notice that the article also refers to Mac machine was hijacked within 10 minutes, I mean it has become an accepted fact that Mac is even now with its Free BSD base struggling to keep their security tight, and now the Open Source OSs are falling off their "Super Secure" throne.

I mean this no small issue, 16 bit encryption makes your valuable information widely available to many, and if you don't know how to brute force, you can always use the tools made by others -> http://blogs.zdnet.com/security/?p=1102

It is so strange that the time has finally come when Vista as a Windows platform in the midst of all the criticism is consistently rising as far more secure.

I wonder if this is going to raise any controversial topics at the upcoming MVP Interop Workshop (http://dotnet.org.za/zlatan/archive/2008/06/04/mvp-interoperability-workshop-will-be-rockin.aspx)

Posted by Zlatan | 11 comment(s)
Filed under: ,

MVP Interoperability Workshop will be rockin'!!!!

 

So most of you already know about the MVP Workshop that is coming up in Jozi next week, for those of you don't know check out the following posts:

http://dotnet.org.za/willy/archive/2008/06/03/mvp-interoperability-workshop-event-agenda-now-you-should-see-that-it-is-worth-attending.aspx

http://dotnet.org.za/willy/archive/2008/05/30/mvp-interoperability-workshop-the-sponsors-behind-the-scenes.aspx

http://dotnet.org.za/willy/archive/2008/05/28/mvp-interoperability-workshop.aspx

http://www.saarchitect.net/

So I will also be heading for Jozi (staying at the exclusive Villa De Willy) to join in on this madness, where bunch of MVP misfits and other keen members from the community discuss why we should all work together, both the penguin and the butterfly.

I mean, to quote Rodney King, "Why can't we all just get along?!?"

So if you want to catch me and say "Hi", also listen to me argue the point on why should PHP developers (traditionally using the Open Source platform) migrate their PHP sites to the Microsoft platform and why would that even make sense, come to our MVP Interop Workshop. We'll also feed you and give you some really cool prizes!!!

Posted by Zlatan | 1 comment(s)
Filed under: , ,