Archive

Archive for the ‘.Net’ Category

Unit testing our MVC Controller for Sitecore

10/07/2012 Leave a comment

Is this post and as promised, we will unit test the controller we created in the last post.
So we will rewrite the controller a tiny little bit, so we can inject a child item repository, ie. creating a stub for the repository. Since Sitecore as default doesn’t ship with ControllerFactory where it is possible use dependency inject we will rewrite the controller instead, so it has a default repository it uses when Sitecore is instantiating the controller, and one it uses when testing, or more precisely you can pass one in to Repository property. The updated controller code is listed below. In my next post we will extend Sitecore so we can inject class through the contructor with dependency Inject using Ninject.

public class ItemController : Controller
{
private IChildItemRepository _childItemRepository;

public JsonResult Index(string id)
{
return Json(CreateObject(ChildItemRepository.Get(id)), JsonRequestBehavior.AllowGet);
}
public IChildItemRepository ChildItemRepository
{
get { return _childItemRepository ?? (_childItemRepository = new ChildItemRepository()); }
set { _childItemRepository = value; }
}

private IEnumerable<object> CreateObject(IEnumerable<Item> items)
{
List<object> objectList = new List<object>();
foreach (Item item in items)
objectList.Add(new { item.Name });
return objectList;
}

}

Now the three test cases
1. No id supplied the controller should return an empty result.
2. Supplied  with an invalide Guid the controller should return an empty result.
3. Supplied with a valid guid, the controller should return a JSon result with  the item names for all child items placed under the node with specified Guid,

Now for the Unit test class, as a mocking framework I’ve used NSubstitute. I’ve used the ItemStub I did in the this post Unit testing with Sitecore Item.  The code for this test Item is also as a service listet below.

public class ItemStub : Item
{
public ItemStub(string itemName)
: base(ID.NewID, new ItemData(new ItemDefinition(ID.NewID, itemName, ID.NewID, ID.NewID),Sitecore.Globalization.Language.Invariant, new Sitecore.Data.Version(1), new FieldList()), new Database("dummy"))
{
}

}

[TestFixture]
 public class ItemControllerTest
 {
 [Test]
 public void ItemControllWithNoIdShouldReturnEmptyList()
 {
 IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 childItemRepositoryStub.Get(Arg.Any<string>()).Returns(new List<Item>());
 ItemController controller = new ItemController();
 controller.ChildItemRepository = childItemRepositoryStub;
 JsonResult result = controller.Index(string.Empty);
 Assert.That(result.Data,Is.Empty);
 }

[Test]
 public void ItemControllWithInvalideIDShouldReturnEmptyList()
 {

IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 childItemRepositoryStub.Get(Arg.Any<string>()).Returns(new List<Item>());
 ItemController controller = new ItemController();
 controller.ChildItemRepository = childItemRepositoryStub;
 JsonResult result = controller.Index("invalidID");
 Assert.That(result.Data, Is.Empty);
 }

[Test]
 public void ItemControllWithValidIdShouldReturnJsonListWithItemNames()
 {
 IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 List<Item> childList = new List<Item>();

childList.Add(new ItemStub("stub-a"));
 childList.Add(new ItemStub("stub-b"));
 childList.Add(new ItemStub("stub-c"));
 childList.Add(new ItemStub("stub-d"));

Guid itemGuid = Guid.NewGuid();
 childItemRepositoryStub.Get(itemGuid.ToString()).Returns(childList);
 ItemController controller = new ItemController();
 controller.ChildItemRepository = childItemRepositoryStub;
 JsonResult result = controller.Index(itemGuid.ToString());

List<object>resultData = (List<object>) result.Data; ;
 Assert.AreEqual(4,resultData.Count());
 Assert.AreEqual(resultData[0].ToString(),"{ Name = stub-a }");
 Assert.AreEqual(resultData[1].ToString(), "{ Name = stub-b }");
 Assert.AreEqual(resultData[2].ToString(), "{ Name = stub-c }");
 Assert.AreEqual(resultData[3].ToString(), "{ Name = stub-d }");
 }

And a screenshot of the test status.

I know that there probably exists better ways to test json results, but it is out of scope for this post, and yes if it should be “clean tests” each test should only contain one assert, but is left for as an exercise for you :).

In the next post we will extend Sitecore so that we can create Controllers through dependency injection, with Ninject as an IoC container. With this solution we don’t need the ugly Set in the Repository Property.

Sitecore MVC the first controller.

03/07/2012 1 comment

Sitecore 6.6 is now out, (as a technical preview), with the realse of this version Sitecore now offers full support for MVC. There have all ready been quite a few blog post how to user MVC with Sitecore and some of the new fetures offers a great deal of ease when developing with Sitecore.

So this is the first in a series of how to develop with Sitecore using MVC and some of the benefits you get for free using MVC.

If you haven’t allready read John West blog post on how to setup you Sitecore solution to use MVC you can read them here start with Part 1 and use part 3 to setup a visual studio solution .John also wrote some simple examples on how to use the MVC framework to return JSON serialized result from a controller you read his original post here. For a first post in this Sitecore MVC series we will revisit his example and create our own controller but with a different approach, and with the soon to be released .Net 4.5 Framework which include the new web-api this should be even easier, and given you even more flexibility for free and out of the box, we will look back at this example when the final release is out.

By now you should now have an up an running Sitecore 6.6 solution. My visual studio solution setup is shown below.

Now lets create our first controller Code listed below.


public class ItemController : Controller
 {

public JsonResult Index(string id)
 {
 return Json(CreateObject(ChildRepository.Get(parentItemId)), JsonRequestBehavior.AllowGet);
 }

private ChildItemRepository _childRepository;
 public virtual ChildItemRepository ChildRepository
 {
 get { return _childRepository ?? (_childRepository = new ChildItemRepository()); }

}

private IEnumerable<object> CreateObject(IEnumerable<Item> items)
 {
 foreach (Item item in items)
 yield return new {item.Name};
 }

}

With the controller in place you can change the route to newly created controller John in his example uses a Pipeline in Sitecore to achieve this i like this approache so much more the using the global.asax so we reuse his code for this with some minor alternations. The Id of the node we want to retrieve children for if not specified default to the id of the Home-node. I’ve done this because i don’t like all his assert for empty id, and if you don’t like you can just use the original approach with optional url parameter.You could if liked alsp default the index action. But instead of getting the id trough the url route data you should supply it as a argument to the action method. The key here is that parameter Id must be named the same as the input parameter in index method.


public class SitecoreMVCRoutes
 {

public virtual void Process(Sitecore.Pipelines.PipelineArgs args)
 {
 this.RegisterRoutes(RouteTable.Routes);
 }

public bool MvcIgnoreHomePage { get; set; }

protected virtual void RegisterRoutes(RouteCollection routes)
 {
 if (this.MvcIgnoreHomePage)
 {
 routes.IgnoreRoute(String.Empty);
 }

routes.MapRoute(
 "Default", // Route name
 "Item/{action}/{id}", // URL with parameters
 new { controller = "Item", action = "Index", id = "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}" } // Parameter defaults with Id to home node
 );
 }
 }

Now we will implement the busyness layer that will supply the controller with data.

This is done through a ChildRepository the code is listed below.

</pre>
public class ChildItemRepository
 {
 public virtual IEnumerable<Item> Get(string parentItemId)
 {
 ID parentId;
 if(ID.TryParse(parentItemId,out parentId))
 return GetChildNodes(parentId);
return new List<Item>();
 }

private IEnumerable<Item> GetChildNodes(ID parentId)
 {
 Item parentItem = Sitecore.Context.Database.GetItem(parentId);
 return parentItem.GetChildren();
 }
 }
<pre>

Lets test the new controller

First with out supplying a id,

Now with a valid id different form the home-node.

And now with a invalid id.

There we go the code does the same as Johns but with out all the assert tests.

Categories: .Net, C#, MVC, Sitecore 6, Uncategorized Tags: , ,

Dropbox integration with Sitecore

16/11/2011 Leave a comment
In this post I will make a simple integration from dropbox into the sitecore media library. This is an early release or more a sneak peak at what I hope in time will be a feature rich sitecore open source project/module  “Dropbox integration with Sitecore” With visioning and two sync, and any request that might come in.
So consider this an Alpha-release, I’ve used this Dropbox Context we build in the last blog post “introduction to the dropbox api“. I’ve changend it a little bit so I can be used to make a static .aspx file where you can build the accestoken file. The changend Dropbox context is shown below
 public class DropboxContext
    {
        private OAuthToken _accessToken;

        private string _applicationKey;

        private string _applicationSecret;
        private string _accessTokenPath;

        private OAuthRestClient _apiRestClient;
        private OAuthRestClient _contentiRestClient;

        private string _version = "1.0";

        public DropboxContext(DropBoxSettings settings)
        {
            _applicationKey = settings.ApplicationKey;
            _applicationSecret = settings.ApplicationSecret;
            _accessTokenPath = settings.AccessTokenPath;
            SetupApiRestClient();
            SetupContentRestClient();
        }

        private void SetupApiRestClient()
        {
            _apiRestClient = new OAuthRestClient("https://api.dropbox.com");
            _apiRestClient.ConsumerKey = _applicationKey;
            _apiRestClient.ConsumerSecret = _applicationSecret;
            _apiRestClient.Version = _version;
        }

        private void SetupContentRestClient()
        {
            _contentiRestClient = new OAuthRestClient("https://api-content.dropbox.com");
            _contentiRestClient.ConsumerKey = _applicationKey;
            _contentiRestClient.ConsumerSecret = _applicationSecret;
            _contentiRestClient.Version = _version;
        }

        public OAuthToken GetRequestToken()
        {

            return new OAuthToken(_apiRestClient.GetRequestToken("1/oauth/request_token"));

        }

        public void AuthorizeToken(OAuthToken token)
        {
            Process.Start("https://www.dropbox.com/1/oauth/authorize?oauth_token=" + token.Token);
        }

        public void SetAccesToken()
        {
            OAuthToken accesToken = GetAccesTokenFromStore();
            if (accesToken == null)
            {
                OAuthToken requestToken = GetRequestToken();
                AuthorizeToken(requestToken);
              //  accesToken = UpgradeRequsetTokenToAccesToken(requestToken);
            }

            _accessToken = accesToken;
        }

        public void UpgradeRequsetTokenToAccesToken(OAuthToken requestToken)
        {
            if (requestToken == null)
                return;

            string tokenString = _apiRestClient.GetAccesToken("1/oauth/access_token", requestToken);
            OAuthToken token = new OAuthToken(tokenString);
            StoreAccessToken(tokenString);

        }

        public void StoreAccessToken(string tokenString)
        {
            FileStream fs = File.Open(_accessTokenPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            StreamWriter sw = new StreamWriter(fs);
            sw.WriteLine(tokenString);
            sw.Close();
            fs.Close();

        }

        private OAuthToken GetAccesTokenFromStore()
        {
            OAuthToken token = null;
            string tokenString = TokenStringFromFile();
            if (!string.IsNullOrEmpty(tokenString))
                token = new OAuthToken(tokenString);

            return token;
        }

        private string TokenStringFromFile()
        {
            FileStream fs = File.Open(_accessTokenPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            StreamReader sw = new StreamReader(fs);

            string tokenString = sw.ReadToEnd();
            sw.Close();
            fs.Close();
            return tokenString;
        }

        public AccountInfo AccountInfo()
        {
            var response = _apiRestClient.QueryServer<AccountInfo>("1/account/info", GetAccesTokenFromStore());
            return response;
        }

        public FileEntry GetMetadata(string path)
        {
            string requestPath = "1/metadata/dropbox";
            if (!String.IsNullOrEmpty(path))
                requestPath = String.Format("{0}{1}", requestPath, path.ToLower());
            var response = _apiRestClient.QueryServer<FileEntry>(requestPath, GetAccesTokenFromStore());
            return response;
        }

        public byte[] GetFile(string path)
        {
            var response = _contentiRestClient.GetStream("1/files/" + path, GetAccesTokenFromStore());
            return response;
        }
    }

Since this i an early release I’ve build this simple .aspx page that provides the user with a link to allow acces to their dropbox and writes the accesToken to a flat file, the file can we then copy to the sitecore data folder for later use.

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    Token : <%# Token.Token %> <br />
    Token Secret  <%# Token.TokenSecret %><br />

    <a href="https://www.dropbox.com/1/oauth/authorize?oauth_token=<%# Token.Token %>" target="_blank">Autherize Dropbox</a>

    <asp:Button ID="Button2" Text="Store Token" runat="server" onclick="Button2_Click" />
    </div>
    </form>
</body>
</html>
 public partial class AutherizeDropBox : System.Web.UI.Page
    {
        private OAuthToken token;
        private DropboxContext context;
        protected void Page_Load(object sender, EventArgs e)
        {
            context = new DropboxContext(SitecoreDropboxSettingsRepository.Get());

            if (!IsPostBack)
            {

                DataBind();
            }
        }

        protected void Page_PreRender(object sender, EventArgs e)
        {

        }

        protected  OAuthToken Token
        {
            get
            {
                if (ViewState["token"] != null)
                {
                    token = new OAuthToken();
                    token.Token = ViewState["token"].ToString();
                    token.TokenSecret = ViewState["tokenSecret"].ToString();
                }
                if (token == null)
                {
                    token = context.GetRequestToken();
                    ViewState["token"] = token.Token;
                    ViewState["tokenSecret"] = token.TokenSecret;
                }
                return token;
            }
        }

        protected void Button2_Click(object sender, EventArgs e)
        {

                OAuthToken t = Token;
                context.UpgradeRequsetTokenToAccesToken(t);

        }
    }

For dropbox context to work we need a valid dropboxcontext setting datacontainer. Information for this i stored as settings in the web.config

   <setting name="ApplicationKey" value="YOURAPPLIKATIONKEY" />
   <setting name="ApplicationSecret" value="YOURAPPLIKATIONSECRET" />
   <setting name="AccessTokenPath" value="PATHTOYOUFILETHATCONTAINSACCESSTOKEN" />

For this simple version of dropbox syncing I’ve build a simple sitecore task to run a “Download all service” from dropbox. It’s start by deleting all old the previously downloaded content from dropbox and the download from all content from dropbox root ie. “dropbox/”.

public class DropboxDownloadTask
    {
        CreateMediaItemService _createMediaItemService;
        public void Execute()
        {
            _createMediaItemService = new CreateMediaItemService();
            GetRoot();
        }

        private void GetRoot()
        {
            MetatadataRepository metatadataRepository = new MetatadataRepository();
            FileEntry root = metatadataRepository.Get();
            IterateOverChildren(root);
        }

        private void  IterateOverChildren(FileEntry folderEntry)
        {

            foreach (FileEntry entry in folderEntry.Contents)
            {
                if (entry.Is_Dir)
                  IterateOverChildren(GetFileEntry(entry));
                else
                  _createMediaItemService.CreateMediaItem(entry);
            }
        }

        private FileEntry GetFileEntry(FileEntry entry)
        {
            MetatadataRepository metatadataRepository = new MetatadataRepository();
            return metatadataRepository.Get(entry);
        }
    }

The task uses some file- and metadata-repositories that communicate with dropboxcontext and a simple settings repository.

 public static class SitecoreDropboxSettingsRepository
    {
        public static DropBoxSettings Get()
        {
            DropBoxSettings settings = new DropBoxSettings();
            settings.ApplicationKey = Settings.GetSetting("ApplicationKey");
            settings.ApplicationSecret = Settings.GetSetting("ApplicationSecret");
            string path = Settings.GetSetting("AccessTokenPath");
            settings.AccessTokenPath = HttpContext.Current.Server.MapPath(path);
            return settings;
        }

    }
public class MetatadataRepository
    {
        private DropboxContext _context;
        public MetatadataRepository()
        {

            _context = new DropboxContext(SitecoreDropboxSettingsRepository.Get());
        }

        public FileEntry Get()
        {
            return _context.GetMetadata(String.Empty);
        }

        public FileEntry Get(FileEntry entry)
        {
          return _context.GetMetadata(entry.Path);
        }
    }
 public class FileDataRepository
    {
        private  DropboxContext _context;
        public FileDataRepository()
        {

            _context = new DropboxContext(SitecoreDropboxSettingsRepository.Get());
        }

        public  byte[] Get(FileEntry entry)
        {
          return _context.GetFile(entry.Root+entry.Path);
        }
    }

Finally the task have a simple service that is responsible for adding a media stream to the sitecore media library.

 public class CreateMediaItemService
    {

        private MediaCreator _creator;
        private MediaCreatorOptions _mediaOptions;

        public void CreateMediaItem(FileEntry folderName)
        {
                 using (new SecurityDisabler())
                          AddStreamToMediaLibrary(folderName);

        }

        private void AddStreamToMediaLibrary(FileEntry folderName)
        {
             if(folderName.Parent == "dropbox")
                 SetMediaOptions(folderName.Parent, folderName.Name);
            else
                SetMediaOptions(String.Format("dropbox/{0}",folderName.Parent), folderName.Name);
            _creator = new MediaCreator();

            FileDataRepository fileDataRepository = new FileDataRepository();
            byte[] bytes = fileDataRepository.Get(folderName);

            MemoryStream theMemStream = new MemoryStream();

            theMemStream.Write(bytes, 0, bytes.Length);
            try
            {

                    _creator.CreateFromStream(theMemStream, folderName.Name, _mediaOptions);
            }
            catch (Exception e)
            {
                throw new Exception(folderName.Name, e);
            }
        }

        private void SetMediaOptions(string sitecorePath, string itemName)
        {
            _mediaOptions = new MediaCreatorOptions();
            _mediaOptions.FileBased = false;
            _mediaOptions.IncludeExtensionInItemName = false;
            _mediaOptions.KeepExisting = false;
            _mediaOptions.Versioned = false;
            _mediaOptions.Destination = String.Format("/sitecore/media library/{0}/{1}", sitecorePath, ItemUtil.ProposeValidItemName(itemName));
            _mediaOptions.Database = Database.GetDatabase("master");

        }

    }

Offcourse there are room for improvement and the code could use some cleaning up to is more “Clean Code” Uncle Bob.  You can download the source code for this project at Pentia. I’m more then interrested in hearing what features should be on the todo-list so let me know.

Categories: .Net, C#, Sitecore 6 Tags: , ,

Introduction to the dropbox api version 1.0

02/11/2011 2 comments

In this post i will explore some of the basic functionality of the new Dropbox Api, you can read more about here https://www.dropbox.com/developers/reference/api. As you can see in the description you talk to dropbox using rest, and OAuth as authentication method. I could of course buil my own OAuth helper instead i will use this OAuth base utility found at https://www.dropbox.com/developers/reference/api  not that i that think it written as clean “clean code”  I like it does the job, but i will give some trouble writting clean crisp method of some of the classes in this post. As a restclient  I will use the client from  http://restsharp.org/.
Some of the code in this post is also done very naive with no error handling so of course if you want to use the code one should deffently address this issue.

Before you start coding anything you first need to go to dropbox and create an app
https://www.dropbox.com/developers/apps

The app key and app secret should be replaced where necessary  through out this post.

The authentication process at dropbox consist of three steps

  1. Get a request token
  2. Authorize the request token from step 1
  3. Upgrade the access token from step 1 to an Access token. The Access token should nt be stored and can be used in all future interaction with dropbox.

First a Token from dropbox i delivered from a rest response in form given below

oauth_token_secret=b9q1n5il4lcc&oauth_token=mh7an9dkrg59

So i made this simple yet  NOT VERY CLEAN CODE CLASS

public class OAuthToken
    {
        public OAuthToken()
        {
        }

        public OAuthToken(string tokenString)
        {
            string[] urlParts = tokenString.Split('&');
            string[] secretParts = urlParts[0].Split('=');
            string[] tokenParts = urlParts[1].Split('=');
            TokenSecret = secretParts[1];
            Token = tokenParts[1];
        }

        public string TokenSecret { get; set; }
        public string Token { get; set; }
    }

Most of the other restquest a response with Json and the restsharp can deserialize them in datacontainers.

Now with token class in place we can create the firs rest call to supply us with at instance of a request token.

We first need some dropbox OAuth settings stored in this datacontainer

public class DropBoxSettings
    {
        public string ApplicationKey { get; set; }
        public string ApplicationSecret { get; set; }
        public string AccessTokenPath { get; set; }
    }

With this we can create a new OAuthrestClient

public class OAuthRestClient
    {
        private OAuthBase _oAuth;
        private RestClient _restClient;

        public OAuthRestClient(string restHost)
        {
            _oAuth = new OAuthBase();
            _restClient = new RestClient(restHost);
        }

        public string GetRequestToken(string resource)
        {
            RestRequest request = AddOAuthParameters(resource);
            RestResponse response = _restClient.Execute(request);
            return response.Content;
        }

        public string GetAccesToken(string resource,OAuthToken token)
        {
            RestRequest request = AddOAuthParameters(resource,token);
            RestResponse response = _restClient.Execute(request);
            return response.Content;
        }

        public T QueryServer<T>(string resource, OAuthToken token) where T : new()
        {
            RestRequest request = AddOAuthParameters(resource, token);
            RestResponse<T> restResponse = _restClient.Execute<T>(request);
            return restResponse.Data;
        }

        public byte[] GetStream(string resource, OAuthToken token)
        {
            RestRequest request = AddOAuthParameters(resource, token,false);
            RestResponse restResponse = _restClient.Execute(request);
            return restResponse.RawBytes;
        }

        private RestRequest AddOAuthParameters(string resource, OAuthToken token=null,bool encodeSignatur=true)
        {
            RestRequest request = new RestRequest(Method.GET);
            string nonce = _oAuth.GenerateNonce();
            string timeStamp = _oAuth.GenerateTimeStamp();
            request.Resource = resource;

            request.AddParameter("oauth_consumer_key", ConsumerKey);
            request.AddParameter("oauth_nonce", nonce);
            request.AddParameter("oauth_signature_method", "HMAC-SHA1");
            request.AddParameter("oauth_timestamp", timeStamp);
            if(token != null)
                request.AddParameter("oauth_token", token.Token);
            request.AddParameter("oauth_version", "1.0");
            request.AddParameter("oauth_signature", BuildSignatureWithToken(resource, nonce, timeStamp, token, encodeSignatur));
            return request;
        }

        private string BuildSignatureWithToken(string resource, string nonce, string timeStamp, OAuthToken token,bool encodeSignature)
        {
            string normalizedUrl;
            string normalizedRequestParameters;
            string sig;
            if(token == null)
             sig = _oAuth.GenerateSignature(new Uri(string.Format("{0}/{1}", _restClient.BaseUrl, resource)), ConsumerKey, ConsumerSecret, "", "", "GET", timeStamp, nonce, out normalizedUrl, out normalizedRequestParameters);
            else
             sig = _oAuth.GenerateSignature(new Uri(string.Format("{0}/{1}", _restClient.BaseUrl,resource)),ConsumerKey, ConsumerSecret,token.Token, token.TokenSecret,"GET", timeStamp, nonce, out normalizedUrl, out normalizedRequestParameters);

            if(encodeSignature)
                sig = HttpUtility.UrlEncode(sig);
            return sig;
        }

        public string Version { get; set; }
        public string ConsumerKey { get; set; }
        public string ConsumerSecret { get; set; }
    }

There are som input parameters that are bool which i due some restriction bugs in the OAuth base where a token not should be added in the requesttoken call. And the dropbox api where the signature shouldn’t be urlencode when querying api-content.dropbox.com. We can now use this to get a request token.

  public OAuthToken GetRequestToken()
        {
            OAuthRestClient apiRestClient = new OAuthRestClient("https://api.dropbox.com");
            apiRestClient.ConsumerKey = YOUR APP KEY;
            apiRestClient.ConsumerSecret = YOUR APP SECRET;
            apiRestClient.Version = "1.0";
            return new OAuthToken(_apiRestClient.GetRequestToken("1/oauth/request_token"));
        }

Now with request token we can prompt the user for access to his or hers dropbox account this can for now only be done in a browser

private void AuthorizeToken(OAuthToken token)
        {
            Process.Start("https://www.dropbox.com/1/oauth/authorize?oauth_token=" + token.Token);
        }

Now with application authorized we ca upgrade the requesttoken to an accestoken, and store it in a secure place for now we store it as a string in a plaintext file.

 private OAuthToken UpgradeRequsetTokenToAccesToken(OAuthToken requestToken)
        {
 OAuthRestClient apiRestClient = new OAuthRestClient("https://api.dropbox.com");
            apiRestClient.ConsumerKey = YOUR APP KEY;
            apiRestClient.ConsumerSecret = YOUR APP SECRET;
            apiRestClient.Version = "1.0";
            string tokenString = apiRestClient.GetAccesToken("1/oauth/access_token", requestToken);
            OAuthToken token = new OAuthToken(tokenString);
            StoreAccessToken(tokenString);
            return token;
        }

        private void StoreAccessToken(string tokenString)
        {
            FileStream fs = File.Open(_accessTokenPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            StreamWriter sw = new StreamWriter(fs);
            sw.WriteLine(tokenString );
            sw.Close();
            fs.Close();

        }

        private OAuthToken GetAccesTokenFromStore()
        {
            OAuthToken token = null;
            string tokenString = TokenStringFromFile();
            if(!string.IsNullOrEmpty(tokenString))
             token = new OAuthToken(tokenString);

            return token;
        }

        private string TokenStringFromFile()
        {
            FileStream fs = File.Open(_accessTokenPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            StreamReader sw = new StreamReader(fs);

            string tokenString =  sw.ReadToEnd();
            sw.Close();
            fs.Close();
            return tokenString;
        }

Now with an accestoken we can start talking to dropbox to the more fun stuff for example the userinformation

public class AccountInfo
    {
        public string Uid { get; set; }
        public string Display_Name { get; set; }
        public string Country { get; set; }
        public QuotaInfo Quota_Info { get; set; }
    }
 public class QuotaInfo
    {
        public string Shared { get; set; }
        public string Quota { get; set; }
        public string Normal { get; set; }
    }

or metadata for a a given path in the users dropbox

 public class FileEntry
    {
        public string Size { get; set; }
        public string Rev { get; set; }
        public string Thumb_Exists { get; set; }
        public string Bytes { get; set; }
        public string Modified { get; set; }
        public string Path { get; set; }
        public bool Is_Dir { get; set; }
        public string Icon { get; set; }
        public string Root { get; set; }
        public string Mime_Type { get; set; }

        public string Revision { get; set; }
        public List<FileEntry> Contents { get; set; }

        public string Name
        {
            get
            {

                if (String.IsNullOrEmpty(Path)) return String.Empty;
                if (Path == "/") return "dropbox";
                    return Path.Substring(Path.LastIndexOf("/") + 1);
            }
        }

        public string Parent
        {
            get
            {
                if (String.IsNullOrEmpty(Path)) return String.Empty;
                if (Path.LastIndexOf("/") == 0) return "dropbox";
                return Path.Substring(0,Path.LastIndexOf("/"));

            }
        }

    }
public AccountInfo AccountInfo()
        {
            OAuthRestClient apiRestClient = new OAuthRestClient("https://api.dropbox.com");
            apiRestClient.ConsumerKey = YOUR APP KEY;
            apiRestClient.ConsumerSecret = YOUR APP SECRET;
            apiRestClient.Version = "1.0";
            var response = apiRestClient.QueryServer<AccountInfo>("1/account/info", YOUR ACCES TOKEN);
            return response;
        }</pre>
&nbsp;
<pre>


Now we could can the byte[]  for a dropbox entry if it is not a folder, note when calling the api-content.dropbox.com the SIGNATURE PASSED TO DROPBOX SHOULD NOT BE URL -ENCRYPTED why i have no clue

public byte[] GetFile(string path)
        {
          OAuthRestClient apiRestClient = new OAuthRestClient("https://api-content.dropbox.com");
            apiRestClient.ConsumerKey = YOUR APP KEY;
            apiRestClient.ConsumerSecret = YOUR APP SECRET;
            apiRestClient.Version = "1.0";
            var response = apiRestclient.GetStream("1/files/dropbox/" + HttpUtility.UrlEncode(path), YOURRACCESTOKEN);
            return response;
        }

I’ve gathered all the functions in a simple Dropbox context.

So this wraps it up for now. in future post I will look into uploading files, but in the next post I will integrate this into the sitecore media library, for now only with download only and always overwrite. Coming soon so stay tuned.

Categories: .Net, C# Tags: , , ,

Running Scheduledtasks with the jobmanager in Sitecore

06/10/2011 5 comments

I’ve recently had the need to execute a scheduled task. The simple way would be to fetch the scheduled task item from Sitecore an instantiate it as a ScheduledItem type found in Sitecore kernel namespace, and the Call the execute method found in the class.


Item item = database.GetItem(taskId);
 ScheduleItem scheduleItem = new ScheduleItem(item);
 scheduleItem.Execute();

This of course Will run the task in the context of the current user. This could lead to some minor issues where the user running task doesn’t have the same rights as the Sitecore build JobManager.The solution is to execute the task via the JobManager, which also is used by scheduler. This is done by providing simple JobOptions. The example belows instantiate a new MyTask and runs the execute method.

 JobOptions options = new JobOptions("Job Runner", "schedule", "scheduler", new MyTask(), "Execute", new object[] { scheduleItem.Items,  scheduleItem.CommandItem, scheduleItem });
 options.SiteName = "scheduler";
 JobManager.Start(options).WaitHandle.WaitOne();

The last parameter passed in as a new object is the parameter list passed on to the Execute Method.

 

Categories: .Net, C#, Sitecore 6 Tags:

Loosely couple ninject kernel in MVC applications

27/07/2011 Leave a comment

I’m currently working on a hobby project “a photosite”, where I’m using MVC 3 with Entity Framwork 4 and Ninject IOC container. Maybe I overdid the decoupling of the Ninject kernel for this project, but I was fun to do and I gave material for this post :). The goal was to build a MVC project where the repository implementation was placed in separate project together with ninject binding.

So here is the repository Interaface:

public interface IGalleryRepository
{
   IEnumerable<Gallery> All { get; }
}

And here is the concrete implementation for the interface

public class GalleryRepository : IGalleryRepository
{
   PhotoSiteContext context = new PhotoSiteContext();
   public IEnumerable<Gallery> All
   {
    get { return context.Galleries; }
   }
}

Now we need to alter the global.asax file with the following.

public class MvcApplication : NinjectHttpApplication
{
   public static void RegisterGlobalFilters(GlobalFilterCollection filters)
   {
     filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Gallery", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();

AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
      {
var kernel = new StandardKernel();
kernel.Load(AppDomain.CurrentDomain.GetAssemblies());
return kernel;
}
}

By loading the kernel this way Ninject will looke through all dll’s in the bin folder of MVC project “main project” and load all assemblies which inherit from the NinjectModul class.

Now we cant in same project as the implementation of the inteface make a new class which derives from Ninject modul. The class should look like this.

public class SqlCompactNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IGalleryRepository>().To<GalleryRepository>();
}
}
With this setup it would be possible to switch the gallery implementation simply by adding a new dll with a NinjectModule and a concrete implementation of the IgalleriInterface.
I hope you find this usefull.
Categories: .Net, MVC Tags: , , ,

Seamless integration of external photo gallery

12/03/2010 Leave a comment

In this post I will give one way, or my take on how-to integrate an external photo gallery seamless in to your website. Some of the advantage in doing this is you save room/space on your local webhost, and the load on the serve if you have large photo/images since these are not load in another thread on an external server. Off course there are disadvantage as well the gallery provide have to be online for this to work, and you have to maintain gallery content and web content on two different websites. On the other hand you if you choose one of the large providers flickr or picasa, you get some great photo gallery functionality tagging of images and galleries and more.

So i don’t what to build the new Picasa or a like, so i will only provide functionality for showing frontend relevant images and associated information. In near future there will be a post on how-to use this post to integrate into Umbraco.

For this post i have chosen to integrate up against Google’s Picasa so to start with you can go and download the google-gdata API you can get it here

The documentation i used to for making this post and code can be found here
The main idea for making this seamless is it could be easy to switch gallery provider from picasa to whatever your favorite web-photo gallery you use. Off course the difficulties you meet depend on how well an interface the provider gives you, you could end up in some tricky situations.
Okay let’s get started. First of I’ve created the interfaces I’ve so necessary for making a good web gallery. You are more than welcome to give feedback if you think something are missing on one these.

There exist three parts. A gallery which consists of one or more photo albums. Next there off course a photo album which contain some album information and one or more Images. Last off is the image it self. So here are the three interfaces.

public interface IGallery
{
String Name { get; }
String Description { get; }
int NumberOfAlbums { get; }
IEnumerable Albums{get;}
IGalleryAlbum GetAlbumFromId(string id);
}


public interface IGalleryAlbum
{
String Id { get; }
String Name{ get; }
String Description { get; }
String Category { get; }
IGalleryImage AlbumCoverImage { get; }
uint NumberOfImages { get; }
IEnumerable Images { get; }
}
public interface IGalleryImage
{
String Name { get; }
String Url { get; }
String Description { get; }
String ThumbnailUrl { get; }
Dictionary ExifData { get; }
}

Again you are more than welcome to give feedback if you think something is missing, keep in mind this is what I think is one a good and simple image gallery should be able to provide of information.
So now we have the interfaces in place lets go ahead an implement them using the Picasa API.
This is a pretty simple task if keep a window open with the documentation here is another link to the documentation
All I’ve used is the simple example provide at the documentation page.
First of the gallery implementation this is simple.


namespace PicasaGalleryModel
{
public class PicasaGallery : IGallery
{
private PicasaService _service;
private PicasaFeed _feed;

private const string PICASA_SERVICE_NAME = "PicasaIGalleryModel";

public PicasaGallery(string username)
{
Username = username;
}

public string Name
{
get
{
return Feed.Title.Text;
}
}

public string Description
{
get { return ""; }
}

public int NumberOfAlbums
{
get { return Albums.Count(); }
}

public IEnumerable Albums
{
get
{
return InitializeGalleryAlbumFromPicasaFeed();
}
}

public IGalleryAlbum GetAlbumFromId(string id)
{
return Albums.Where(g => g.Id == id).First();
}

private PicasaFeed Feed
{
get
{
if (_feed == null)
_feed = RetrieveUserAlbumsFromPicasa();
return _feed;
}
}

private PicasaFeed RetrieveUserAlbumsFromPicasa()
{
AlbumQuery query = new AlbumQuery(PicasaQuery.CreatePicasaUri(Username));
PicasaFeed feed = Service.Query(query);
return feed;
}

private IEnumerable InitializeGalleryAlbumFromPicasaFeed()
{
foreach (PicasaEntry entry in Feed.Entries)
{
IGalleryAlbum album = new PicasaAlbum(entry,Service,Username);
yield return album;
}

}

private PicasaService Service
{
get
{
if(_service == null)
_service = new PicasaService(PICASA_SERVICE_NAME);
return _service;
}
}

private void Logon()
{
}

protected string Password
{
get;
set;
}

protected string Username
{
get; set ;
}
}
}

DO note that the username is the logon name you use to logon to picasa.
The implementation have some unused and unfinished function, when I first the idea to this post it started as huge project where I wanted security from picasa as well to be covered, in this implementation.
Wow this class uses the IGalleryAlbum so let’s move on to the implantation of this.


namespace PicasaGalleryModel
{
public class PicasaAlbum : IGalleryAlbum
{
private PicasaEntry _albumFeed;
private PicasaFeed _imageFeed;
private AlbumAccessor _ac;

public PicasaAlbum(PicasaEntry feed,PicasaService service,string username)
{
AlbumFeed = feed;
Service = service;
Username = username;
}

public string Name
{
get { return AlbumAccessor.AlbumTitle; }
}

public string Description
{
get { return AlbumAccessor.AlbumSummary; }
}

public string Category
{
get { return "CAT-SET_STATIC"; }
}

public IGalleryImage AlbumCoverImage
{
get
{
PhotoQuery query = PhotoQueryFromUri(AlbumFeed.Id.AbsoluteUri);
return BuildIGalleryImageFromPicasa(Service.Query(query)).First();
}
}

private AlbumAccessor AlbumAccessor
{
get
{
if (_ac == null)
_ac = new AlbumAccessor(AlbumFeed);
return _ac;
}
}

public uint NumberOfImages
{
get
{

return AlbumAccessor.NumPhotos;
}
}

public IEnumerable Images
{
get
{
return BuildIGalleryImageFromPicasa(ImageFeed);
}
}

private IEnumerable BuildIGalleryImageFromPicasa(PicasaFeed feed)
{
foreach (PicasaEntry entry in feed.Entries)
{
IGalleryImage image = new PicasaImage(entry);
yield return image;
}
}

public PicasaEntry AlbumFeed
{
get { return _albumFeed; }
set { _albumFeed = value; }
}

public PicasaFeed ImageFeed
{
get
{
if(_imageFeed == null)
{

_imageFeed = Service.Query(PhotoQueryFromUri(PicasaImageUri()));
}
return _imageFeed;
}
}

private string PicasaImageUri()
{
return PicasaQuery.CreatePicasaUri(Username, Id);;
}

private PhotoQuery PhotoQueryFromUri(string uri)
{
return new PhotoQuery(uri);
}

private PicasaService Service
{
get; set;
}

public String Id
{
get
{
return AlbumAccessor.Id;
}
}

private string Username
{
get;
set;
}
}
}

And now to the final part the Image implementation


namespace PicasaGalleryModel
{
public class PicasaImage : IGalleryImage
{

private PhotoAccessor _photoAccessor;

private Dictionary _exifData;

public PicasaImage(PicasaEntry entry)
{
Entry = entry;
}

private PicasaEntry Entry
{
get;
set;
}

public string Name
{
get
{
return PhotoAccessor.PhotoTitle;
}
}

public string Url
{
get
{
return Entry.Media.Content.Attributes["url"].ToString();
}
}

public string Description
{
get { return PhotoAccessor.PhotoSummary; }
}

public string ThumbnailUrl
{
get
{
return Entry.Media.Thumbnails[0].Attributes["url"].ToString();
}
}

public Dictionary ExifData
{
get
{
if (_exifData == null)
InitializeExifDataToDictionary();
return _exifData;
}
}

private void InitializeExifDataToDictionary()
{
_exifData = new Dictionary();
_exifData.Add("Camera model", Entry.Exif.Model.Value);
_exifData.Add("ISO", Entry.Exif.ISO.Value);
_exifData.Add("Focal Length", Entry.Exif.FocalLength.Value);
//_exifData.Add("Exposure", Entry.Exif.Exposure.Value);
_exifData.Add("F Stop", Entry.Exif.FStop.Value);
_exifData.Add("Flash", Entry.Exif.Flash.Value);
}

public PhotoAccessor PhotoAccessor
{
get
{
if(_photoAccessor == null)
_photoAccessor = new PhotoAccessor(Entry);
return _photoAccessor;
}
}

}
}

Now with the model in place we can start to render out the IGallery* stuff.
This is made so it should be easy to integrate into Umbraco hence the MasterPage file.
The frontend stuff consist of the main gallery which loads in two different controls depending on you are viewing a list of albums or a list images in an album. The styling is left for you do, since this is dependent on your website design. If you like a can In a later post do this.
The main gallery

The .ascx page


<%@ Page Language="C#" MasterPageFile="~/Gallery.master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Presentation._Default" %>
 <%@ Import Namespace="Interfaces" %>

<asp:Content ID="head" ContentPlaceHolderID="head" Runat="Server">
 <script type="text/javascript" src="js/jquery.js"></script>
 <script type="text/javascript" src="js/jquery.lightbox-0.5.min.js"></script>
 <script type="text/javascript" src="js/InitLightbox.js"></script>
 <link rel="stylesheet" type="text/css" href="/CSS/jquery.lightbox-0.5.css" media="screen" />
 </asp:Content>

 <asp:Content ID="GalleryContent" ContentPlaceHolderID="GalleryContent" Runat="Server">

<div>

My Gallery Test


<asp:PlaceHolder ID="galleryContent" runat="server" />

</div>
 </asp:Content>

and the codepage


public partial class _Default : System.Web.UI.Page
{
private IGallery _gallery;
public const string ALBUMID = "aid";

protected void Page_Load(object sender, EventArgs e)
{

SetGalleryContent();
}

private void SetGalleryContent()
{
Control view;
if (String.IsNullOrEmpty(AlbumId))
view = LoadGalleryView;
else
view = LoadAlbumView;
galleryContent.Controls.Add(view);
}

private IEnumerable GalleryAlbums
{
get
{
return Gallery.Albums;
}
}

private Control LoadGalleryView
{
get
{
Control viewControl = LoadControl("~/GalleryView.ascx");
GalleryView gallery = (GalleryView)viewControl;
gallery.AlbumQueryString = ALBUMID;
gallery.GalleryAlbums = GalleryAlbums;
return viewControl;
}
}

private Control LoadAlbumView
{
get
{
Control viewControl = LoadControl("~/AlbumView.ascx");
AlbumView gallery = (AlbumView)viewControl;
gallery.Images = CurrentAlbum.Images ;
return viewControl;
}
}

private IGalleryAlbum CurrentAlbum
{
get
{
return Gallery.GetAlbumFromId(AlbumId);
}
}
private string AlbumId
{
get
{
return Request.QueryString[ALBUMID];
}
}

private IGallery Gallery
{
get
{
if(_gallery == null)
_gallery = new PicasaGallery("USERNAME_GOES_HERE");
return _gallery;
}
}
}

The List view of albums Ascx page


<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="GalleryView.ascx.cs" Inherits="Presentation.GalleryView" %>
 <%@ Import Namespace="Interfaces"%>

<asp:Repeater runat="server" ID="AlbumeRepeater" DataSource="<%# GalleryAlbums %>">
 <ItemTemplate>
 <div>
 <a href="<%# AlbumLink(((IGalleryAlbum)Container.DataItem).Id) %>" >
 <img src="<%# ((IGalleryAlbum)Container.DataItem).AlbumCoverImage.ThumbnailUrl %>" alt="" />
 </a>
 </div>
 <div>
 <a href="<%# AlbumLink(((IGalleryAlbum)Container.DataItem).Id) %>" >
 <%# ((IGalleryAlbum)Container.DataItem).Name %>
 </a>
 </div>
 <div>
 <%# ((IGalleryAlbum)Container.DataItem).NumberOfImages %>
 </div>
 <div>
 <%# ((IGalleryAlbum)Container.DataItem).Description%>
 </div>

 </ItemTemplate>
 </asp:Repeater>

Codepage


public partial class GalleryView : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
AlbumeRepeater.DataBind();
}

public string AlbumLink(string albumId)
{
string url = String.Format("{0}{1}={2}", Request.RawUrl, AlbumQueryString, albumId);
return url;
}

public string AlbumQueryString
{
get; set;
}

public IEnumerable GalleryAlbums
{
get;
set;
}

}

And finally the list view of images in an album
Ascx page


<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="AlbumView.ascx.cs" Inherits="Presentation.AlbumView" %>
 <%@ Import Namespace="Interfaces"%>
 <asp:Repeater ID="ImageRepeater" runat="server" DataSource="<%#Images %>">
 <HeaderTemplate>
 <ul id="Gallery">
 </HeaderTemplate>
 <ItemTemplate>
 <li>
 <a href="<%# ((IGalleryImage)Container.DataItem).Url %>" class="lightbox" title="<%# ExifData((IGalleryImage)Container.DataItem)%>"><img src="<%# ((IGalleryImage)Container.DataItem).ThumbnailUrl %>" /></a>

 </li>
 </ItemTemplate>
 <FooterTemplate>
 </ul>
 </FooterTemplate>
 </asp:Repeater>

Codepage


public partial class AlbumView : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
ImageRepeater.DataBind();
}

public string ExifData(IGalleryImage image)
{
string exifData = "";
foreach(string key in image.ExifData.Keys)
{
exifData += string.Format("{0} : {1}<br>
", key, image.ExifData[key]);
}
return exifData;
}

public IEnumerable Images
{
get;
set;
}
}

The final part is using the jquery lightbox again you could switch this to you own favorite gallery viewing service the lightbox for jquery can be found here. I’ve extend this a bit so you can provide a max image height and max image width, both are found in the solution for this project.
And a service for my loyal readers, you can now download the entire solution which contains all the above models implementations, and all the other good stuff I’ve covered in this post.  And now you can head over and see when this is integrated into umbraco, i’ve done this for my site here is a like to my gallery

Categories: .Net, C# Tags: , ,

Adding captcha “Recaptcha Umbraco Blog”

22/01/2010 Leave a comment

So after i my self got spammed by a lot of robots on my blog i browsed the internet to find an easy way to add captcha for the comment part of my blog.

So i found the easiest way to do was using recaptcha, which can be found here recaptcha.net. So before we start head over there and create an account.

Step 1:

Create recaptcha.net account  recaptcha.net

Step 2:

Download the .Net package containing the recaptcha.dll

Step 3:

Download from you site frmBlogComment.ascx placed in siteroot/usercontrols

Step4:

Edit frmBlogComment.ascx

add the following lines

These lines should be right after the “control tag” “<%@ Control …… %>”

Futher down you can now add the recaptcha usercontrol


<recaptcha:RecaptchaControl
 ID="recaptcha"
 runat="server"
 PublicKey=...
 PrivateKey=....
 />

ofcourse with your privatekey and publickey..

Step 5:

Upload recaptcha.dll to your webroot/bin

Upload the newly edited  frmBlogComment.ascx to you webroot/usercontrols/

And you should be all done and no more bots should spam your blog I hope.

This post is for them that dont want to recompile umbraco, it would be a much better solution to add an reference to the recaptcha.dll

Categories: .Net Tags: ,

Flv files in IIS

03/06/2009 Leave a comment

To make iis server flv files you need to add the .flv extension to the minetypes for the website.

1. Open the site to configure in IIS. Right click and select “Properties”
2. Click the HTTP Headers Tab, select “File Types” under the MIME Map section, and then click “New Type”. Enter the following:
* Associated Extension box: .flv
* MIME Type box: flv-application/octet-stream
3. Click “OK” and close the IIS Properties box
4. You may need to restart the WWW Publishing Service

Categories: .Net Tags: