Last umbraco login straight from sql

by Damiaan Peeters 25. November 2014 13:33

If you ever want to have the last login's from your back-end users this is usefull SQL it converts the stored ticks 

select userid , userlogin , useremail, DATEADD(ms, ((ticks - 599266080000000000) - 
   FLOOR((ticks - 599266080000000000) / 864000000000) * 864000000000) / 10000,
   DATEADD(d, (ticks - 599266080000000000) / 864000000000, '01/01/1900')) +
   GETDATE() - GETUTCDATE()
from (
SELECT l.[userID] as userid, u.userLogin as userlogin, u.useremail as useremail
      , min([timeout]) as ticks
  FROM [db16284].[dbo].[umbracoUserLogins] l
  inner join umbracouser u on l.userid = U.id
  where l.userid <> 0
  group by l.userid, u.userLogin, u.useremail
  ) t1
  order by userid desc

Tags:

Umbraco Backoffice integration with Active Directory

by Damiaan Peeters 12. February 2014 10:43

Add the AD membership provider to the web.config in the system.web/membership/providers section

<add name="ADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0,Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
connectionStringName="ADConnectionString"
attributeMapUsername="sAMAccountName" />

In the connectionstrings section of the web.config

<add name="ADConnectionString" connectionString="LDAP://server001/DC=commit,DC=local" />

Change in config/umbracoSettings.config

  <providers>
    <users>
      <!-- if you wish to use your own membershipprovider for authenticating to the umbraco back office -->
      <!-- specify it here (remember to add it to the web.config as well) -->
      <!--<DefaultBackofficeProvider>UsersMembershipProvider</DefaultBackofficeProvider>-->
      <DefaultBackofficeProvider>ADMembershipProvider</DefaultBackofficeProvider>
    </users>
  </providers>

Deleting all dictionary item from the umbraco dictionary

by Damiaan Peeters 21. December 2013 19:38

Sometimes you need to delete all dictionary items from the Umbraco dictionary. 

The problem

Deleting 100’s of dictionary items can be a PITA.  Imagine you have to right click for every dictionary item and select delete.

image

Side information

First you probably want to know which tables the dictionary is using.  There are 2: one for the items, one for the translations.  They call cmsDictionary and cmsLangaugeText. 

If you ever want to get information from the dictionary, just join these tables and you have what you need.

select d.pk, lt.pk, d.[key], lt.languageId, l.languageISOCode, lt.value
from cmsDictionary d inner join cmsLanguageText lt on d.id = lt.UniqueId
left join umbracoLanguage l on lt.languageId = l.id
where d.pk = 6

Solution

The fastest way to remove all umbraco dictionary items is through SQL.  To remove ALL dictionary items, just run this SQL script:

delete from cmsLanguageText
delete from cmsDictionary

Don’t forget to touch the web.config because dictionary items are heavily cached!

Did you know this is default in Umbraco?

by Damiaan Peeters 8. December 2013 15:18

A few days ago I got the question from a manager: “Is this default in Umbraco?” To be honest, that is a very difficult question that deserves a blog post on it’s own.  So here it is!  The answer to a general question asked to an umbraco developer: "Is this default in Umbraco?"

Short answer

It is probably a default setup on how you can work with Umbraco.  So: yes.

Slightly longer answer

It depends of course on what you call “default”.  But the developer you are asking this question, has probably implemented the things asked already a few times.  Been there, done that.  And if he hasn’t done so, he might have found a blog post or forum topic which explains how to do so.  Or maybe he has found (a free) package, which does the things considered to be default.

The reason why the developer can say it is default, is packages, blogs and extending umbraco IS default.  Without the default behaviour, you would not have a website. 

Long answer

First of all, I wrote earlier that Umbraco is not a CMS, I called it a framework.  Umbraco provides a base for you to build web applications (or websites), without trying to interfere with the developers using it.

Umbraco does not provide strict guidelines on how to setup your website.  It does not force information into predefined concepts.  As such the developer need to (sic, by default) extend the Umbraco download, in order to have a website.  The nice thing about Umbraco, is that it doesn’t limit you in how you organise everything to get things done.  It gives you a solid base where you can plug in different things.

The core of Umbraco exists out of an amount of default modules.  These modules take care of rendering your webpages, building URL’s, saving and publishing content items (nodes) and rendering backend.  These modules are “default”, but no-one would not expect otherwise from a CMS.  That's why you are not writing your own rendering engine, but instead choose a CMS. 

A lot of modules in the Umbraco Core can be replaced or extended by your own needs.  I consider replacing these modules, or adding extra functionality to modules ALSO default.  A developer familiar with the concerned topics (extending umbraco and dev’s reference), doesn’t need to know all the internals to add easy customizations to your website.  This is were a lot of power of umbraco comes from, and is to my knowledge not always easy to do with other cms’s. Extending the base is daily job, and can be considered default.

If the core is not enough, there are a lot of packages.  Packages are pieces of software which are developed by 3th parties (except for Courier, Contour and Concierge), which add extra functionality to Umbraco.  Most packages are free, some not.  Packages are build for Umbraco, and the Umbraco back-end makes it very easy to install addons.  I think we can safely say that most Umbraco installations use packages.  This makes me believe the Umbraco Packages are default.  If someone would try too argue against, consider that there are packages which are now included (or parts of it) into to core (like uGoLive, uComponents, …).

One of the great side effects of having such a Robust core is that a lot of package creators, implement the same robust principles in there software.  This makes it for packages developers easy to plug into events of 3th party packages, and “customize” this further.

If you read up till here, you might wonder: all this customization sounds like pretty expensive.  I can’t talk for other companies, or what they are charging for certain functionality.  In our experience, Umbraco offers a lot of extendable default functionality speeding up development.  This gives the customizations in question a much higher return on investment, compared to Umbraco-less solutions.

So what do you think?  What do you consider "default" in umbraco?

Smart homepage switching on HTTP accept-language headers

by Damiaan Peeters 1. December 2013 10:18

Http Headers

Every time time a browser requests a webpage from a web server, there are headers added to the the request.  Information like: Give me page X, I accept HTTP, you can Gzip or deflate data, proxy information, …

On of these http headers are the “Accept-Language” http headers.  So what does these headers mean?

Each language-range MAY be given an associated quality value which represents an estimate of the user's preference for the languages specified by that range.

If you open your browser hit F12, you can find for every request the headers back.  The accept language headers can look like this:

image

This means: I prefer Dutch, but will accept US English or any English dialect if available.  Every user can change the browser settings to reflect their language preference.

Sometimes – from a user design perspective, using the http headers to show understandable content to the user might be a good idea.  A lot of UX experts argue pro and/or contra.  We won’t go into the discussion because this is mainly a technical blog.  Let’s just try to implement it, because we can!  Glimlach

The solution

I’ll be using the IContentFinder for the solution. Never heard of the ContentFinderResolver?  Then read my previous blogpost or some official umbraco documentation.

I think that this is one of the cases where you can use IContentFinder to control what Umbraco serves to the rendering process.  We need to start with adding a new entry to the ContentFinderResolver.  This time we want it to be launched before the default umbraco implementation.  We can do this by using the following code:

ContentFinderResolver.Current.InsertTypeBefore<ContentFinderByNiceUrl, MyCustomHttpAcceptLanguageContentFinder>();

The rest of the idea is simple, for all root content nodes, search back the “Domain” object, and check whether the language matches.

try {
  string acceptLanguage = HttpContext.Current.Request.UserLanguages[0].Split('-')[0];
  string domainName = System.Web.HttpContext.Current.Request.Url.Host.ToLower();
  var rootDocs = UmbracoContext.Current.Application.Services.ContentService.GetRootContent();
  foreach (var rootDoc in rootDocs)
  {
    var domains = Domain.GetDomainsById(rootDoc.Id);

    var domainmatch = domains.FirstOrDefault(domain => domain.Language.CultureAlias.StartsWith(acceptLanguage));
    if (domainmatch != null)
    {
        contentRequest.PublishedContent = rootDoc;
        continue;
     }
  }
} catch {
  // search engines don't send language-accept headers
}

Attention, this is a very basic implementation and not ready for production at all! 

The SEO Warning

Like mentioned in the code: take care when implementing a solution using accept-language.  Googlebot is NOT sending any accept language headers along.  So be sure that you don’t get trapped in sending empty pages or (500) errors to the Search Engines.

With that I would like to ask, do you consider this as a valid use of IContentFinder?  What other Content Finders do you have in mind?  Have you already used the ContentFinderResolver?

From the legacy INotFoundHandler to IContentFinder.

by Damiaan Peeters 21. November 2013 09:05

If you are developing a custom “page not found” policy in Umbraco, then you know pretty good the “INotFoundHandler”.  

The old procedure is pretty straightforward. Create a new class which implements the INotFoundHandler interface and add an extra line in your “404handlers.config” file.  Done.

Did you know the INotFoundHandlers are replaced by IContentFinder?

Why bother

Are you really wondering why you would use the new interface “IContentFinder”, while the INotFoundHandler is still working.

First of all, the new IContentFinder  is documented.  How awesome is that? 

The INotFoundHandlers will become obsolete in the future.  So no reason to stay on legacy stuff. 

ContentFinders are very stable,  Umbraco v6 already uses ContentFinders to serve your content.  This is not instable alpha stuff you are looking at.

Notice the name change.  We go from “not found” to “content finder”.  That means that you can do a lot more than just handling not found requests.  That’s right!  You can now write your own blasting super geeky content finder which can serve any IPublishedContent (probably content from the tree). 

This new IContentFinder is a part of the request pipeline.  That means that IContentFinder classes can handle any request which is handled by Umbraco.  But this also means that you can insert your custom class before the normal Umbraco flow of searching elements by the “nice url”. 

A few examples:

  • If you don’t like the awesome 301 package UrlTracker by kipusoep, and you are considering building your own, you would want to use the new IContentFinder interface. 
  • If you are working with a multi site & multi language with a difficult 404 page setup, you just write your own 404 handler (and call the SetIs404() method on the PublishedContentRequest).
  • If you want to write your own rewriting rules against against some external database, you could use the IContentFinder
  • Serve content from a custom datasource.  I’ll try to discuss this briefly in another post.

How it works

First write your own ContentFinder.  You can do this by creating a new class, which implements the IContentFinder interface.  The only method you need is the TryFindContent.  Set the “PublishedContent” property to the node you want to returned to the user and return TRUE.  If your contentfinder did not found any content return FALSE so others can give there shot.

If you have a node you want to show as 404, put the node as the “publishedContent” property, call SetIs404  and return TRUE.

public class MyCustomContentFinder : IContentFinder 
{ 
    public bool TryFindContent(PublishedContentRequest contentRequest) 
    { 
        LogHelper.Debug<MyCustomContentFinder>("TryFindContent({0})", () => contentRequest.Uri.ToString());
if (contentRequest == null) { return contentRequest.PublishedContent != null; } var contentCache = UmbracoContext.Current.ContentCache; var foundContent = contentCache.GetById(1234); contentRequest.PublishedContent = foundContent; // contentRequest.SetIs404(); return contentRequest.PublishedContent != null; } }

To let Umbraco use the IContentFinder above, you will need to add the class to the ContentFinderResolver.  In this case we will insert it before the legacy “NotFoundHandlers”:

public class Custom404Launcher : ApplicationEventHandler
{
    protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
    {
        LogHelper.Info<Custom404Launcher>("Attaching MyCustomContentFinder as IContentFinder");
        ContentFinderResolver.Current.InsertTypeBefore<ContentFinderByNotFoundHandlers, MyCustomContentFinder>();
    }
}

Watch (tail) the umbraco Log file with powershell

by Damiaan Peeters 6. November 2013 19:02

Situation

Sometimes you want to watch the umbraco Log file.  You doubelclick the file in explorer time after time.  Scroll down and look what was added on the bottom.  If you ar lazier (smarter?), then you would open WebMatrix or Visual studio leave the file open and just click yes when it reloads.

If you are still looking for the log files: go to /app_Data/Logs/UmbracoTraceLog.txt

Watching while it moves?

if you ever used linux then you are probably already missing the TAIL command for ages.  We have a solution: powershell to the rescue!  Make sure you have installed powershell version 3.

Then create a new powershell file (eg. mylogviewer.ps1) in the root of the website. Paste in the code below: 

gc App_Data\Logs\UmbracoTraceLog.txt -Tail 10 -Wait

When you run this powershell command, you will see the that powershell stays active and will update the screen as soon as new lines arrive in your LogFile.  If you don't want to create the file yourself, i have added it compressed below.

LogTail.zip (170.00 bytes)

Bing Maps DataType for umbraco

by Damiaan Peeters 7. October 2013 15:21

Update 2: Also available as a package on our.umbraco.org
Update: made code available on github

When we create websites, we almost always use the excellent Google Maps DataType to let the users update their contact page themselves.  But sometimes, your customer tells you that you can’t use Google Maps.  For political reasons.  Let’s say a Microsoft sponsored website for example.

That’s why I created quickly something that resembles the Google Maps DataType, and I called it “Bing Maps DataType”. It’s not as clean and well build as the GMDT, but I got something. And it works.

Get your key

If you develop public websites using Bing Maps, you need an API key.  To request a free key, go to http://www.bingmapsportal.com, click on “Create or view keys” and create a new key.
A basic key is free of charge for a limited usage amount.

Creating the usercontrol

In the website, I’ve created a usercontrol using a code behind.   This is the code, mainly javascript:

<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="BingMapPropertyEditor.ascx.cs"
Inherits="UserControls_BingMapPropertyEditor" %>
<asp:TextBox runat="server" ID="txtLocation" /> <script charset="UTF-8" type="text/javascript"
src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"> </script> <script> $(function () { var loc = document.getElementById("<%= txtLocation.ClientID %>").value; var mapOptions = { zoom: 8, credentials: '<%= BingKey %>' }; if (loc !== '') { mapOptions.center = new Microsoft.Maps.Location(loc.split(',')[0], loc.split(',')[1]); mapOptions.zoom = parseInt(loc.split(',')[2]); } map = new Microsoft.Maps.Map(document.getElementById('mapDiv'), mapOptions); // add default pin var pushpin = new Microsoft.Maps.Pushpin(mapOptions.center, { 'draggable': true }); map.entities.push(pushpin); var attachclick = Microsoft.Maps.Events.addHandler(map, 'click', function (e) { if (e.targetType == "map") { map.entities.clear(); var point = new Microsoft.Maps.Point(e.getX(), e.getY()); var loc = e.target.tryPixelToLocation(point); var location = new Microsoft.Maps.Location(loc.latitude, loc.longitude); var pushpin = new Microsoft.Maps.Pushpin(location, { 'draggable': true }); map.entities.push(pushpin); document.getElementById("<%= txtLocation.ClientID %>").value =
location.latitude + "," + location.longitude + "," + map.getTargetZoom(); } }); }); </script> <div id='mapDiv' style="position:relative; width: <%= MapWidth %>; height: <%= MapHeight %>;"> </div>

and this is my codebehind.

using umbraco.cms.businesslogic.datatype;
public partial class UserControls_BingMapPropertyEditor 
: System.Web.UI.UserControl,
umbraco.editorControls.userControlGrapper.IUsercontrolDataEditor { [DataEditorSetting("Bing Maps key", description="get your key on http://www.bingmapsportal.com/")] public string BingKey { get; set; } [DataEditorSetting("Width", defaultValue = "400px")] public string MapWidth { get; set; } [DataEditorSetting("Height", defaultValue = "450px")] public string MapHeight { get; set; } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { txtLocation.Text = value.ToString(); } } public object value { get { return txtLocation.Text; } set { txtLocation.Text = value.ToString(); } } }

Create a datatype

I used the IUsercontrolDataEditor to create a UserControl.  After I dropped the usercontrol in the usercontrols folder, I created a datatype:

image

Language in HTML tag

by Damiaan Peeters 4. September 2013 12:48

According to W3 we should put a language attribute in our HTML tag. I’ve seen a lot of ugly and unmaintainable solutions for putting language tags in the HTML.  With MVC the problem is less

With ugly I mean the following: you don’t want to encapsulate one tag in a macro.  Do you?  As you might know, I hate inline macro’s anyway.

<umbraco:Macro language=”cshtml” runat=”server”>
<html lang=”@Model.Lang”>
</umbraco:Macro>

with unmaintainable I mean:

<html lang=”<umbraco:item field=”lang” runat=”server” recursive=”true”/>”>

You don’t want to allow the user to choose and mistype the language.   Certainly because you already set the culture on the root node?

Set culture on root node

If you haven’t you should.  It’s not difficult.  Right click the home page node, and choose “Manage hostnames”.

image

The best solution?

If you have set the culture on the parent node, you can reuse default “CurrentCulture” ASP.net object to pick up the language.  I’ve added the namespace so that it works for less technical readers, but you could strip that out off course.

<html lang="<%= System.Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.ToLower() %>">

If you use MVC in umbraco it’s even more readable:

<html lang=”@System.Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.ToLower()”>

How do you solve this?  Let me know in the comments!

Thread safety and adding items to dictionaries

by Damiaan Peeters 13. August 2013 14:52

I was looking at some code from Zack Owens “Multi Tenancy Sample”.  He has some clever code, a ThreadSafeDictionary with a GetOrAdd method. I love the idea!  (code below for my own reference)

The problem with a dictionary, is that – apparently - .Net puts somewhere a system wide lock to ensure thread safety on a dictionary anyway.  That’s the reason that, if you are working with huge dictionaries with lots of READS, you might bump into some performance issues.  In such cases, you could (and should) use the ConcurrentDictionary from the System.Collections.Concurrent namespace.  And if you are looking at this class, visit the BlockingCollection from the same namespace also, still trying to wrap my head around it, but it is ultra important.  You just feel it when reading through the MSDN article.

   /// DON’T USE THIS CODE – You probably want a System.Collections.Concurrent.ConcurrentDictionary

   using System;
   using System.Collections.Generic;
   using System.Threading;

   /// <summary>
   /// Dictionary that has a "GetOrAdd" method that is thread-safe
   /// </summary>
   /// <typeparam name="TKey">Dictionary key</typeparam>
   /// <typeparam name="TValue">Dictionary value</typeparam>
   public class ThreadSafeDictionary<TKey, TValue> : Dictionary<TKey, TValue>
   {
       /// <summary>
       /// Lock for adding values
       /// </summary>
       private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();

       /// <summary>
       /// Gets a value or adds the value in a thread-safe way
       /// </summary>
       /// <param name="key">Key in the dictionary</param>
       /// <param name="defaultValue">Delegate that will get the value</param>
       /// <returns>Value from the dictionary with given <paramref name="key"/></returns>
       public TValue GetOrAdd(TKey key, Func<TValue> defaultValue)
       {
           // enter read lock
           this.cacheLock.EnterReadLock();

           try
           {
               // test if value is in the dictionary
               if (this.ContainsKey(key))
                   return this[key];
           }
           finally
           {
               // exit read lock
               this.cacheLock.ExitReadLock();
           }

           // enter write lock
           this.cacheLock.EnterWriteLock();
           try
           {
               if (!ContainsKey(key))
                   this.Add(key, defaultValue());
               return this[key];
           }
           finally
           {
               // exit write lock
               this.cacheLock.ExitWriteLock();
           }
       }
   }

Who.I.am

Certified Umbraco, .net and Azure developer, seo lover. Magician in my spare time.

Month List