Upgradeing to Blogengine 1.6

by Jesper Persson 14. March 2010 12:55

The process of upgradeing to Blogengine 1.6 from 1.4.5 was really easy, unfortunately my new and super cool implementation of fancy ajax capcha is no longer to be found on my blog, and since the new version has a better administration of blog comments/spam, I doubt it will return.

Tags:

Generel

Enable fancy JQuery captcha in Blogengine 1.4.5.0 (UPDATED)

by Jesper Persson 9. March 2010 22:10

First of all you need to download the files from here http://www.webdesignbeach.com/ajax-fancy-captcha-php.zip I won’t waste time writing how to install the files since there is a good explanation on the website http://www.webdesignbeach.com/beachbar/ajax-fancy-captcha-jquery-plugin

But copy the files into your Blogengine folder

 

The first problem I faced was that it was made with PHP in mind and since BlogEngine are using .NET I had to change the captcha.php file to a .NET version.
So I created a new file in the captcha folder called captcha.aspx looking like this:

<%@ Page Language="C#" AutoEventWireup="true" %>
<%
    if(Request["REQUEST_METHOD"] == "POST" && !string.IsNullOrEmpty(Request["captcha"]) && Request["captcha"] == Session["captcha"])
 {
  Response.Write( "Passed!"); /* YOUR CODE GOES HERE */
  Session["captcha"] = string.Empty; /* this line makes session free, we recommend you to keep it */
 }
else if(Request["REQUEST_METHOD"] == "POST" && !string.IsNullOrEmpty(Request["captcha"]))
 {
  Response.Write("Failed!");
 }
/* in case that form isn't submitted this file will create a random number and save it in session */
else
 {
    Random r = new Random();
   
  int random = r.Next(0,4);
  Session["captcha"] = r.Next(0,4);;
        Response.Write(Session["captcha"]);
 }
     %>

I really don’t care much about anything  in here besides the Session handling that’s because .NET and Blogengine both submits form data using javascript and I don’t like to mess with the mechanics so nothing special happens here, except the random numbers generated.

The original plug-in was made so a post could not happen without the right icon was chosen, but in this version the submit button is merely disabled/enabled.

Make sure that you have enabled session in the web.config or nothing will happen.

In the jquery.captcha.js file find the following line and comment it out

 //$("#" + options.formId).append("<input type=\"hidden\" style=\"display: none;\" id=\"captcha\" name=\"captcha\" value=\"" + rand + "\">");

Insert thes after the line above
$("#captcha").val(rand);

Next a little configuration of Blogengine is required, bear in mind that this is only tested in version 1.4.5.0, but in the settings page the references to the scripts are inserted


 <script type="text/javascript" src="../latest-jquery/jquery-1.3.2.min.js"></script>
 <script type="text/javascript" src="../latest-jquery-ui/jquery-ui-1.7.2.custom.min.js"></script>

<script type="text/javascript" src="../captcha/jquery.captcha.js"></script>
 <link href="../captcha/captcha.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" charset="utf-8">
$j = jQuery.noConflict();
 $j(document).ready(function(){
       $j("#btnSaveAjax").attr("disabled","disabled");
  $j(function() {
   $j(".ajax-fc-container").captcha({
    borderColor: "silver",
    text: "Verify that you are a human,<br />drag <span>scissors</span> into the circle."   });
  });
  });
 </script>

BlogEngine uses the $ sign too so in order to avoid problems with JQuery make sure that you add $j = jQuery.noConflict(); that cause some grief on my behalf but luckily I found this blog http://www.dscoduc.com/2008/09/jquery-goodness-for-blogenginenet/

Back in the file system locate the User Controls folder in BlogEngine and open the CommentView.aspx file and insert the following:
<!-- Begin of captcha --> 
<div class="ajax-fc-container">You must enable javascript to see captcha here</div>
<!-- End of captcha -->

This is the container for the Plugin so place it somewhere fitting like before the submit button. Before this line: 
<input type="button" id="btnSaveAjax" value="<%=Resources.labels.saveComment %>" onclick="if(Page_ClientValidate('AddComment')){AddComment()}" tabindex="7" />   

Insert the following line in the same file <input type="hidden" name="captcha" id="captcha" value="" /> this is the value generated by the captcha script.

Lastly you must edit the AddComment() method in the blog.js file after all the variable declarations replace:

 WebForm_DoCallback('ctl00$cphBody$CommentView1',argument, callback,'comment',null,false);

with
var cap = $("captcha");
if(cap.value != "") {
  WebForm_DoCallback('ctl00$cphBody$CommentView1',argument, callback,'comment',null,false);
}

This will make sure the submit will never run unless the hidden field has a value. Alternatively you could move the check into the comments.ascx.cs file and  check the value against the session value. But so far I have'nt got any spam.

That’s it time will tell if it solves the spam problem but why don’t try it out and leave a comment.

Pretty neat if I might say so, all credits to http://www.webdesignbeach.com of cause.


 

Tags: , ,

BlogEngine.NET

Assigning values to more then one property using Lambda expressions

by Jesper Persson 20. August 2009 10:31

I got an interesting question today. "Is it possible to assign values to more then one property in a collection. Using List.ForEach(Action<T>) and lambda expressions?"

Well how hard can that be so I naturally googled it, and came up with no usable results what so ever, I dont blame Google here might be me thats using the wrong search expression. The closest I could get was this article on MSDN: http://msdn.microsoft.com/en-us/library/bb397687.aspx

I dont think this is something you do every day, and I have a hard time figuring out why this was desireable but then again i did'nt ask.

First we need a class:

class test
{
  public int prop1 { get; set; }
  public int prop2 { get; set; }
}

Next a small console application:

class Program
{
  static void Main(string[] args)
  {
   
List<test> l = new List<test>();
    l.Add(
new test());
    l.Add(new test());
    l.ForEach(p => { p.prop1 = 2; p.prop2 = 4; });
   
foreach (test item in l)
    {
     
Console.WriteLine(item.prop1 + item.prop2);
    }
    Console.ReadLine();
  }
}

Tags: , ,

Certified Scrum Master

by Jesper Persson 3. July 2009 14:46

I just recieved my certification as a scrum master so I just wanted to flash my brand new certificate on my blog

Tags: , ,

Mobile LOB webpart pages in Sharepoint

by Jesper Persson 17. June 2009 16:53

One of the things Microsoft never quit has got its grip about is the support for mobile devices in Sharepoint, I know that it’s possible to get mobile views of lists and navigation by appending an m to the url like this http://servername/m what this does is simply redirecting you to /_layouts/mobile/mbllists.aspx page, one thing comes to mind here is that you are redirected to the _layouts folder which indicates this is an application, the pages are of the SPMobilePage type which inherits System.Web.UI.MobileControls.MobilePage that inherits the normal Page class like a normal LayoutsPageBase does via UnsecuredLayoutsPageBase.

But what’s the problem?

The problem as I see it are that you do not have a way of extending the pages with webparts if you need it, and on the other hand if you create a normal web part page and saves it to a page library the total page size will be very large and prevent the mobile device performing at a acceptable pace.

This is caused by Sharepoint, because it injects links to external js and css files that the device must load. I was recently hired as a consultant where the customer used Sharepoint and integrated with DynamicsAX.

Dynamics comes with a lot of webparts that was required to run on a Motorola hand terminal, which was used to scan barcodes. The problem was that the total page size was so large that the terminal was slowed down; the users didn’t need any special rights on the portal so Site Actions was not shown, and the need for the webpart menu wasn’t needed either.

But whenever Sharepoint sees a webpart it automatically loads core.css, init.js, ie55up.js (depending on browser) and core.js.

The challenge

We need to be able to select what the page returns depending on what you want to do. E.g. editing a page or using it from a hand terminal. So we need a way to control the output from Sharepoint without scarifying the functionality of the page. The goal was that an entire page must not exceed 10kb.

The measurements

I created a new master page based on the default.master called mobile.master, and a new page for testing purposes called mobilepage.aspx.

I used Fiddler2 to measure the payload of the page the result was as follows:

Even with everything removed from the Mobilepage.aspx and the masterpage we still have a payload of approx. 150KB that’s about 15 times more than acceptable also the chart says it all, about 80% is javascript, which is totally unnecessary in this scenario, in this demo the only thing want to show is this:

 

Naturally a more rich webpart will be used in a real world scenario.

Request filters and httpmodule to the rescue

After trying a few different approaches, one of them was to insert <Sharepoint:ScriptLink runat=”server”/> web control into the masterpage. That solved some of the issues concerning the core.js, but that’s only 70KB of the 140KB needed. I was still stuck with a lot of javascript.

Step 1 Create a httpmodule in C#

To do that two things have to be done first create a class that implements the IHttpModule interface and update web.config in the <httpModules> section      

<add name="MobileModule" type="Minimum_Payload.HttpFilter, Minimum Payload, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c23d6c989c59848d" />               

namespace Minimum_Payload
{
 
public class HttpFilter :IHttpModule   
 
{

    #region IHttpModule Members        
     
public void Dispose()       
     
{}
      HttpApplication _context = null;       
     
public void Init(HttpApplication context)       
     
{
           
       
_context = context;
           
       
context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);       
     
}
      void context_ReleaseRequestState(object sender, EventArgs e)        
      
{
        if (string.IsNullOrEmpty(_context.Request.QueryString["mobile"])) return;            
       
_context.Context.Response.Filter = new MobileFilter(_context.Context.Response.Filter);
       
     
}
                     
   
#endregion
   
  
}
} 

One of the requirements was the ability to control whether it was a normal browser or a mobile device, for this demo I choose the querystring.

Step 2 Create the Filter

I used this post as inspiration from 4guysfromrolla

public class MobileFilter : MemoryStream   
{
        Stream _output = null;
        public MobileFilter(Stream output)
        {
            _output = output;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            string page = UTF8Encoding.UTF8.GetString(buffer);
            if(page.ToLower().Contains("<script>"))
            {
                int indexOfScript = page.IndexOf("<script>") + 8;
                int indexOfLastScript = page.IndexOf("</script><SCRIPT LANGUAGE='JavaScript' >");
                page = page.Remove(indexOfScript, indexOfLastScript - indexOfScript);
            }
            if (page.ToLower().Contains("</title>"))
            {
                int indexOfTitle = page.IndexOf("</title>");
                int indexOfLastTitle = page.IndexOf("<title>",indexOfTitle);
                page = page.Remove(indexOfTitle, indexOfLastTitle - indexOfTitle);
            }
            _output.Write(UTF8Encoding.UTF8.GetBytes(page), offset, UTF8Encoding.UTF8.GetByteCount(page));
         }
    }

This filter is very simple and I won't recommend that you use it in a production environment, but as an example it works well. The result of the payload of the page are shown here

smallpayload

Conclusion

It is possible to reduce the payload of the page and truly enable mobile devices using webparts. However I do not think that this scenario are supported by Microsoft and I also think that you should take great care in when using custom httphandlers in Sharepoint. Mainly because all request will pass through it, and this could degrade performance.

Source code

Minimum Payload.rar (8,62 kb)

Tags: , , , , ,

Visual Studio 2010 Beta 1

by Jesper Persson 27. May 2009 05:40

Visual Studio 2010 has been released in Beta 1 so as a Sharepoint developer my first thought was to get my hands on the much advertised Sharepoint templates for Sharepoint. But to my disappointment I was unable to find any, so I guess I just have to wait a little longer

Here's some screenshots of the start page and Add new project.

You have to choose .NET 3.5 and the only two templates are the ones for workflows.

 

Please let me know if this is totally wrong, I would love to try them out.

Tags: ,

How to slipstream Sharepoint with Service pack 2

by Jesper Persson 15. May 2009 15:03

After reinstalling my developement environment so it would run on a Windows 2008 server in 64 bit to accomodate the requirements for a future update to Sharepoint 2010, I found my self searching the web for guides on installing Sharepoint on a 2008 box, I've done it before but naturally I have forgot all about how to do it, so here's a guide to how you should go about that.

First you need to download the two updates for WSS and MOSS respectively,
http://www.microsoft.com/downloads/details.aspx?FamilyId=79BADA82-C13F-44C1-BDC1-D0447337051B&displaylang=en 
http://www.microsoft.com/downloads/details.aspx?familyid=B7816D90-5FC6-4347-89B0-A80DEB27A082&displaylang=en 
just save them to any location you prefer, it's not important.

You need to copy all the sharepoint installation files to you harddrive.

open a command prompt and navigate to the folder where the updates are saved and type the following command:

Select the location of you Sharepoint installation files

 
It's important that you select the Updates folder for the extracted files.

Press OK, a EULA will be shown


Accept the terms and press Continue

Repeat the steps for MOSS SP 2

Select the same folder as before 

Accept the license terms

Verify that all files has been extracted to the Update folder, and you are ready to install Sharepoint

SP 2 is a cumulative update which means that it contains all previously released updates, more info an be found at these KB articles http://support.microsoft.com/kb/953338 http://support.microsoft.com/kb/953334

Enjoy!

Tags: , ,

Modifying Quick launch bar with JQuery

by Jesper Persson 1. April 2009 18:24

The Quick launch bar 

Many people are annoyed with the Quick Launchbar, because it quickly gets very large; I'm going to show how this can be solved with JQuery. I was inspired by a post made by Jan Tielens, you can read more about it here. I'm not going to claim to be any kind of expert with regards to JQuery so it's a learning experience for me too.

But what is wrong?

   

Well, there's nothing wrong with it by default, but it really takes up a lot of space and you need to scroll down the page just to see all the links, like this screenshot, not that many lists but a lot of space taken up. I know it's possible to remove the lists from the quick launch bar but then you need mere clicks to get the information.

It's obvious that this needs to be fixed.

JQuery

Unfortunately all the items in the quick launch are all using the same CSS classes so I haven't been able to find a way (yet) to select the individual sections. So this will only work on all the sub items. Insert this code into a Content Editor Webpart:

<style type="text/css">
   .myRowHighlight {color:red; background-color:#FFCC66}
</style>

<script>
$(document).ready(function()
 {
       $("table[class='ms-navSubMenu2 zz2_QuickLaunchMenu_8']").hide("slow");
       $("table[class='ms-navheader zz2_QuickLaunchMenu_4']").hover
        (
            function() {
                $("table[class='ms-navSubMenu2 zz2_QuickLaunchMenu_8']").show("slow");
            }
        );

       $("#OuterLeftCell").hover
        (
             function() {
                 $("table[class='ms-navSubMenu2 zz2_QuickLaunchMenu_8']").hide("slow"); 
             }
        );
 }
);

</script>

I have tested this in IE8 in normal and compatibility mode, Firefox, Opera and Safari and it looks fine in every one of them.

Update Update I managed to find someone that made a better implementation where the individual sections are expaneded check out this great post http://www.endusersharepoint.com/?p=985

Tags: , ,

Search does not work when accessed remotely

by Jesper Persson 25. March 2009 22:25

After setting up my Virtual PC with MOSS 2007 I tried to access the site from the host, the address did not get resolved by the DNS so I choose to access it by IP, everything worked great but when I used search I got this error:

Object reference not set to an instance of an object.   at Microsoft.Office.Server.Search.WebControls.CoreResultsWebPart.OnLoad(EventArgs e)
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

I found an answer on MSDN you can see it here http://social.technet.microsoft.com/forums/en-US/sharepointsearch/thread/b5afd264-07a8-4f66-9d78-807b11bb6022/ it explained the problem but did'nt really solve it for me because of the DNS issue so I cant use the FQDN.

So the resolution was straight forward I just added the IP in the Alernate Access Mappings.

 

Tags: , ,

How to create your own list styles

by Jesper Persson 20. March 2009 10:36

When you create a new view for a list you can specify different Styles, but you can extend those styles too heres how to: The file are located under C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\GLOBAL\XML\VWSTYLES.XML

Tags: