Saturday, February 25, 2012

Create stretching rounded corners background for web part titles in Sharepoint using CSS2

You most probably know that with CSS3 it became easy to crate nice-looking rectangle areas (e.g. for buttons) with rounded corners and gradient. However in Sharepoint development we are often limited to enterprise requirements which makes impossible using of CSS3 (hopefully during last several years I didn’t have IE6 compatibility requirements, but IE7 is still often mentioned). In this post I will show how to create stretching rounded corners background for web part titles in Sharepoint 2010. In the end of article I will also show how to use it for Sharepoint 2007.

Without CSS3 we have to use images with rounded corners. For this example I used online http://css-tricks.com/examples/ButtonMaker for generating of the nice-looking button and then made images from screenshot. We will need 2 images of the same height:

left:

image

and right:

image

Note that left image should be wider (for this example I trimmed it to fit into blog layout) – it will be used when user stretches browser window horizontally.

After that put the following selectors into your alternate css file:

   1: tr.ms-WPHeader > td { height: 46px; }
   2: tr.ms-WPHeader td.ms-WPHeaderTd { background: url(left.png) no-repeat left top; }
   3: tr.ms-WPHeader td.ms-WPHeaderTd + td { background: url(right.png) no-repeat right top; }
   4: .ms-WPHeader td.ms-WPHeaderTd span { color: white; }

(you may need to fix urls to the images – according to the location of css file it may be e.g. Style library). After you will save changes your web parts will look like this:

image

And the same in edit mode:

image

In Sharepoint 2007 css will be slightly different, but idea remains the same. There is no “ms-WPHeaderTd” class so we need to use first-child pseudo element:

   1: tr.ms-WPHeader > td { height: 46px; 
   2: tr.ms-WPHeader td:first-child { background: url(left.png) no-repeat left top; }
   3: tr.ms-WPHeader td:first-child + td { background: url(right.png) no-repeat right top; }
   4: tr.ms-WPHeader span { color: white; }

Using this technique you will be able to decorate your web parts titles with CSS3-style rounded corners background.

Wednesday, February 22, 2012

Predefined order of executed SQL statements in Linq 2 Sql

On one of the projects we used Linq 2 Sql as ORM for our domain model in Sharepoint application. It doesn’t give you 100% persistence ignorance, however from my point of view it is good alternative keeping in mind that in Sharepoint 2010 we are limited with .Net 3.5 and can’t use e.g. Entity Framework starting from 4 version where codefirst approach was introduced. NHibernate is also can’t be applied in some projects with strong enterprise requirements (don’t ask me why, often we just should live with it). I’m going to write separate post(s) about building testable DDD-style infrastructure for projects with help of Linq 2 Sql soon. Here I would like to share one of the problems which we faced during implementation.

We use transactional logic via modified UnitOfWork pattern. With Linq 2 Sql transactions are implemented via generated DataContext class. We make all modifications in DataContext instance and when everything is ready call DataContext.SubmitChanges(). Here problem came out: SQL statements are executed in the following order:

  • Insert
  • Update
  • Delete

regardless of how you called these operations when perform updates in DataContext. It may cause problems if there are e.g. unique key constraints on the table. E.g. imagine that we have 2 entities:

  • Company
  • Contact

with one-to-many relation. I.e. each Company may have multiple Contacts:

image

Contact.Name should be unique, so we add unique key constraint to the table Contact on Name column. Then we need to update some company and its contacts. In order to update contacts the simplest approach is to remove all old contacts and add new one:

   1: while (company.Contacts.Count > 0)
   2: {
   3:     company.Contacts.RemoveAt(0);
   4: }
   5:  
   6: foreach (var contact in newContacts)
   7: {
   8:     company.Contacts.Add(contact);
   9: }

With this approach you don’t need to care about synchronization of each field in each contact. But what will happen when we will call SubmitChanges? As Linq 2 Sql executes inserts before deletes – it will add contacts which of course may be the same as previous if no changes were made in them. As Contact.Name field is unique – we will get violation of unique key constraint exception.

There are some workarounds available, e.g. here: Workaround LINQ to SQL annoying limitations. Author used reflection in order to change operations order, but I can’t be sure that it doesn’t have any side effects so I didn’t use it in production code. Instead we had to implement more complicated mechanism for updates. Instead of deleting all child contacts and inserting new ones we calculated difference between existing contacts set and new contacts set in order to determine which contacts should be deleted and which added. Also we calculated intersection of 2 sets in order to get list of contacts which should be updated. With this approach predefined operations order in Linq 2 Sql won’t cause exception (assuming that Id and unique Name will remain in one-to-one relation, i.e. that we won’t delete existing item and create new one with the same Name. Instead we will update existing item):

   1: private void syncContacts(Company existingCompany, Company newCompany)
   2: {
   3:     if (existingCompany.Contacts.IsNullOrEmpty() &&
   4:         newCompany.Contacts.IsNullOrEmpty())
   5:     {
   6:         // both are empty - nothing to synchronize
   7:         return;
   8:     }
   9:  
  10:     if (existingCompany.Contacts.IsNullOrEmpty() &&
  11:         !newCompany.Contacts.IsNullOrEmpty())
  12:     {
  13:           // source doesn't contain contacts, but target does. Remove target contacts
  14:           while (newCompany.Contacts.Count > 0)
  15:           {
  16:               newCompany.Contacts.RemoveAt(0);
  17:           }
  18:         return;
  19:     }
  20:  
  21:     if (!existingCompany.Contacts.IsNullOrEmpty() &&
  22:         newCompany.Contacts.IsNullOrEmpty())
  23:     {
  24:         // source contains contacts, but target doesn't. Add contacts to target
  25:         existingCompany.Contacts.ToList().ForEach(c => to.Contacts.Add(c));
  26:         return;
  27:     }
  28:  
  29:     // both source and target contain contacts. Need syncronize them
  30:     var itemsToAdd = existingCompany.Contacts
  31:         .Where(s => newCompany.Contacts.All(t => t.Name != s.Name)).ToList();
  32:     var itemsToDelete = newCompany.Contacts
  33:         .Where(t => existingCompany.Contacts.All(s => s.Name != t.Name)).ToList();
  34:  
  35:     // delete
  36:     itemsToDelete.ForEach(i => to.Contacts.Remove(i));
  37:  
  38:     // update
  39:     existingCompany.Contacts.ToList().ForEach(
  40:         s =>
  41:             {
  42:                 var t = newCompany.Contacts.FirstOrDefault(c => c.Name == s.Name);
  43:                 if (t != null)
  44:                 {
  45:                     this.updateContact(s, t);
  46:                 }
  47:             });
  48:  
  49:     // add
  50:     itemsToAdd.ForEach(i => newCompany.Contacts.Add(i));
  51: }

Here I used convenient extension method IsNullOrEmpty() for enumerations (see Checking For Empty Enumerations). This is more complicated way, however it allowed to avoid violation of unique key constraint. Hope it will help someone who will encounter with the same issue with Linq 2 Sql in their projects.

Tuesday, February 14, 2012

One reason for “The caller was not authenticated by the service” error when WCF proxy is configured via code

Some time ago I faced with the problem when tried to call WCF service from Sharepoint timer job: it threw the following exception: “The caller was not authenticated by the service”. When you will investigate this problem, most of solutions which you will find will say that this error is caused by wsHttpBinding with Message level security, and if you don’t need that – you may rather set security mode to “None” or use basicHttpBinding instead. It was not the case for us – because we had service developed by 3rd party company which used wsHttpBinding and we couldn’t change it.

Notice that we called WCF service from Sharepoint timer job. Sharepoint jobs are executed in separate service process (owstimer). Also we needed to call it from Sharepoint site which is running in w3wp process and has own web.config. When service is called from site we can use web.config for configuring WCF client. But how to configure it when service is called from timer job? Of course you can create owstimer.exe.config file and copy WCF configuration there – but in this case configuration will be duplicated in web.config and in owstimer.exe.config. I found the article which shows interesting solution: Calling WCF Web Services from a SharePoint Timer Job. The idea is that we store WCF configuration in one place (in sites’s web.config. Of course you will need to duplicate it if you have several authentication zones, but if you use SPWebConfigModifications for web.config updates it will be done automatically). In timer job we read web.config using classes from System.Configuration and System.ServiceModel assemblies and construct Binding and EndpointAddress instances using read configuration which then passed to the proxy constructor:

   1: var binding = (Binding)bindingCollectionElement
   2:     .BindingType.GetConstructor(new Type[0]).Invoke(new object[0]);
   3: bindingConfig.ApplyConfiguration(binding);
   4: var address = new EndpointAddress(endpointElement.Address);
   5: var proxy = new MyProxy(binding, address);

I tried to do it like this and got mentioned security exception. As I said all solutions which I found were not applicable for us. After some investigation I found difference between configuration from config and configuration from code: EndpointAddress.Identity property was set to null when it is configured from code.

So I changed code a bit and created EndpointAddress with identity:

   1: private EndpointAddress getEndpointAddress(ChannelEndpointElement endpointElement)
   2: {
   3:     if (endpointElement == null)
   4:     {
   5:         return null;
   6:     }
   7:  
   8:     if (endpointElement.Identity != null && endpointElement.Identity.Dns != null)
   9:     {
  10:         return new EndpointAddress(endpointElement.Address,
  11:             EndpointIdentity.CreateDnsIdentity(endpointElement.Identity.Dns.Value));
  12:     }
  13:     return new EndpointAddress(endpointElement.Address);
  14: }

In this example I used DNS identity, but you may use your identity type here (e.g. user principal identity). After that error disappeared and service was called successfully.

Saturday, February 4, 2012

Camlex.Net 3.1: support of dynamic ViewFields

On this week new version 3.1 of Camlex.Net was released. In this release we added support of the dynamic ViewFields. This feature was requested in one of the discussions on the codeplex Camlex site. I.e. the following new methods were added to the IQueryEx interface:

   1: public interface IQueryEx : IQuery
   2: {
   3:     ...
   4:     string ViewFields(IEnumerable<string> titles);
   5:     string ViewFields(IEnumerable<string> titles, bool includeViewFieldsTag);
   6:     string ViewFields(IEnumerable<Guid> ids);
   7:     string ViewFields(IEnumerable<Guid> ids, bool includeViewFieldsTag);
   8: }

I.e. now you can create list of field names or field ids dynamically and pass it into the Camlex. It will create CAML for ViewFields based on this list. For example the following code:

   1: var items = new [] { "Title", "FileRef" };
   2:  
   3: string caml = Camlex.Query().ViewFields(items);

will produce the following CAML:

   1: <FieldRef Name=\"Title\" />
   2: <FieldRef Name=\"FileRef\" />

I would like to share also some interesting (from my point of view :) ) implementation details. You can easily skip the rest of the post if you are not interested in it. Before version 3.1 there were the following methods (they still exist of course):

   1: public interface IQueryEx : IQuery
   2: {
   3:     string ViewFields(Expression<Func<SPListItem, object>> expr);
   4:     string ViewFields(Expression<Func<SPListItem, object>> expr, bool includeViewFieldsTag);
   5:     string ViewFields(Expression<Func<SPListItem, object[]>> expr);
   6:     string ViewFields(Expression<Func<SPListItem, object[]>> expr, bool includeViewFieldsTag);
   7: }

With these methods we were able to create ViewFields like this:

   1: string caml =
   2:     Camlex.Query().ViewFields(x => new [] { x["Title"], x["FileRef"] });

When add new functionality I wanted to reuse these existing methods in order to avoid creating of extra code. In order to do this the following question should be solved: having array of strings or guids (e.g. { “1”, “2”, “3” }) how to create lambda expression “x => new [] { x[“1”], x[“2”], x[“3”] }”? The solution is quite elegant:

   1: public string ViewFields(IEnumerable<string> titles, bool includeViewFieldsTag)
   2: {
   3:     ...
   4:     return this.ViewFields(this.createExpressionFromArray(titles), includeViewFieldsTag);
   5: }
   6:  
   7: public string ViewFields(IEnumerable<Guid> ids, bool includeViewFieldsTag)
   8: {
   9:     ...
  10:     return this.ViewFields(this.createExpressionFromArray(ids), includeViewFieldsTag);
  11: }
  12:  
  13: private Expression<Func<SPListItem, object[]>>
  14: createExpressionFromArray<T>(IEnumerable<T> items)
  15: {
  16:     return Expression.Lambda<Func<SPListItem, object[]>>(
  17:         Expression.NewArrayInit(typeof(object),
  18:         (IEnumerable<Expression>)items.Select(
  19:             t => Expression.Call(Expression.Parameter(typeof(SPListItem), "x"),
  20:                 typeof(SPListItem).GetMethod("get_Item", new[] { typeof(T) }),
  21:                 new[] { Expression.Constant(t) })).ToArray()),
  22:         Expression.Parameter(typeof(SPListItem), "x"));
  23: }

I.e. we iterate through all items in the list and for each item create expression – access to indexer x[item], and add them to the NewArrayInit expression. Note on the ToArray() call – without it lazy LINQ expression won’t be populated and array initialization will fail.

We are very interested in your feedback. Feel free to contact us via Camlex site on the codeplex.