Saturday, August 3, 2013

Return JSON from asmx when call it using jquery ajax: step by step guide

Some time you still need to configure old asmx web service for working with jquery ajax. Interesting that there is still a lot of questions about different aspects of the subject (even though that people should use WCF with REST endpoints nowadays in .Net stack), so I thought that it will be good idea to summarize all configuration steps in single post.

First of all we need to create asmx service itself which returns some POCO object. Let’s create some abstract QueueService:

   1:  [WebService(Namespace = "http://example.com")]
   2:  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
   3:  [ToolboxItem(false)]
   4:  [ScriptService]
   5:  public class QueueService : WebService
   6:  {
   7:      [WebMethod]
   8:      [ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json)]
   9:      public QueueItem GetQueueItem(string itemId)
  10:      {
  11:          var queueRepository = new QueueRepository();
  12:          var queueItem = queueRepository.GetById(new Guid(itemId));
  13:          return queueItem;
  14:      }
  15:  }

QueueItem class may look like this:

   1:  [Serializable]
   2:  public class QueueItem
   3:  {
   4:      public QueueItemStatus Status { get; set; }
   5:      public int Progress { get; set; }
   6:  }

There are several important notes in the code above. First of all web service class is decorated with ScriptService attribute. Then GetQueueItem() web method is decorated with ScriptMethod attribute with UseHttpGet = false, ResponseFormat = ResponseFormat.Json properties. They say that method will be called via HTTP POST verb (you may make it work GET e.g. with JSONP). And ResponseFormat.Json says that result will be returned in JSON format. Note that in the web method we just return object, we don’t serialize it to JSON by ourselves using e.g. standard JavaScriptSerializer or JSON.Net.

The next step will be changing of the web.config, which should be located in the same folder where asmx file is, or location of asmx file should inherit it from parent folders. Here is the minimal required configuration:

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <configuration>
   3:    <system.web>
   4:      <webServices>
   5:        <protocols>
   6:          <add name="HttpPost"/>
   7:        </protocols>
   8:      </webServices>
   9:      <httpHandlers>
  10:        <remove verb="*" path="*.asmx"/>
  11:        <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  12:      </httpHandlers>
  13:    </system.web>
  14:  </configuration>

Here we allow using of HTTP POST verb for calling of our web service (lines 4-8) and replace default handler of asmx files to ScriptHandlerFactory.

This was the server part. Now we need to consume the web service from jquery ajax. Here is the example:

   1:  $.ajax({
   2:      url: "http://example.com/QueueService.asmx/GetQueueItem",
   3:      type: "POST",
   4:      contentType: "application/json; charset=utf-8",
   5:      data: "{'itemId':'...'}",
   6:      dataType: "json",
   7:      success: function(r) {
   8:          if (!r) {
   9:              // handle error
  10:          }
  11:          var result = r.d;
  12:          if (!result) {
  13:              // handle error
  14:          }
  15:          ...
  16:      },
  17:      error: function(xhr, status, error) {
  18:          // handle error
  19:      }
  20:  });

There are several important notes here as well and without understanding them, you will continuously get “There was an error processing the request” with HTTP 500 Internal server error. First of all we call the web service using POST verb (line 3). Second – we need to specify contentType = "application/json; charset=utf-8" (line 4). Without it ASP.Net won’t treat it as JSON request and call will fail (see this article for details: JSON Hijacking and How ASP.NET AJAX 1.0 Avoids these Attacks). Next important thing is that we need to pass parameters to the web method also in JSON format (line 5). Without it you request won’t even reach the service. End the last thing which you need to note is setting dataType = "json" (line 6).

After this you should be able to consume asmx web service which returns JSON from jquery ajax. If you will check requests in fiddler you should see something like this:

request:

POST /QueueService.asmx/GetQueueItem HTTP/1.1
x-requested-with: XMLHttpRequest
Accept-Language: en-US,fi;q=0.5
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/json; charset=utf-8
Content-Length: 52
Connection: Keep-Alive
Pragma: no-cache

{'itemId':'…'}

response:

HTTP/1.1 200 OK
Content-Length: 152
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET

{"d":{"__type":"QueueItem","Status":0,"Progress":0}}

And there are no any additional efforts needed for serializing/deserializing object to JSON neither on server nor on client. Hope this guide will help in you work.

Tuesday, July 30, 2013

Linq 2 Sharepoint works across site collections in Sharepoint 2013

Do you remember that one of the limitation of Linq 2 Sharepoint 2010 was that it didn’t support cross site collections. Developers found workaround for this limitation, see e.g. here: Using LINQ to SharePoint between site collections. But the fact was that Linq 2 Sharepoint didn’t support cross site collections queries OTB. Microsoft.SharePoint.Linq.DataContext class had only one constructor which receives url of the target web site.

   1:  public DataContext(string requestUrl)
   2:  {
   3:      ...
   4:  }

The good news is that in Sharepoint 2013 new overridden constructor was added to the DataContext class with 2nd boolean parameter crossSiteCollection. So if you need context working with different site collection you need to pass true in this parameter:

   1:  public DataContext(string requestUrl, bool crossSiteCollection)
   2:  {
   3:      ...
   4:  }

I didn’t find any additional parameters in SPMetal parameters schema, so SPMetal still generates strongly typed classes for current site collection only. But it is quite easy to fix: open file with generated data context and find where inheritor of DataContext class calls base constructor:

   1:  public partial class MyDataContext : Microsoft.SharePoint.Linq.DataContext {
   2:      public MyDataContext(string requestUrl) : 
   3:          base(requestUrl) {
   4:          ...
   5:      }
   6:      ...
   7:  }

In the example above this is the line 3. You need to add true to the base constructor call manually, so the final code will look like this:

   1:  public partial class MyDataContext : Microsoft.SharePoint.Linq.DataContext {
   2:      public MyDataContext(string requestUrl) : 
   3:          base(requestUrl, true) {
   4:          ...
   5:      }
   6:  }

After this you will be able to use MyDataContext in order to query data from the list from different site collection.

Sunday, July 28, 2013

User defined fields patterns and Sharepoint

Martin Fowler wrote interesting article about implementing user defined fields functionality: UserDefinedField. He summarized several patterns:

  • Variable state;
  • Pre-defined custom fields;
  • Dynamic schema.

Variable state means including a hashmap field for user-defined fields. With pre-defined custom fields you specify predefined fields like integer_1, integer_2, text_1… and then use only those which are needed. With dynamic schema you add the code which dynamically changes the schema of data storage (calls ALTER TABLE if it is SQL data storage).

As you probably know Sharepoint also allows users to construct own custom content types, add fields, specify field types, etc. It is interesting to note that it also uses Pre-defined custom fields pattern. E.g. there is AllUserData table (which stores the data of lists and doclibs) in the content database which contains a lot of columns:

  • Sharepoint 2007 – 193 columns;
  • Sharepoint 2010 – 192 columns;
  • Sharepoint 2013 – 4026 columns.

These columns look like bit1, bit2, …, datetime1, datetime2, …, float1, float2, …, int1, int2, …, etc. Now we have common pattern name used for this schema. It is also interesting to note the big grow of the columns in Sharepoint 2013 comparing with previous versions, which however didn’t change list and columns limits in Sharepoint 2013 comparing with 2010 (see Software boundaries and limits).

Saturday, July 27, 2013

Problem in KQL with date times and client object model in Sharepoint

Keyword query language (KQL) is the one of the basic ways to perform queries to the search index in Sharepoint 2013. When you use it e.g. in Content by search web parts (ContentBySearchWebPart) in order to show results based on specified parameters you may get the following error:

image

(We didn't understand your search terms. Make sure you're using the proper syntax).

Even stranger that the same page may work correctly (i.e. show search results) in one browser, but broken in another. In our case Content by search web part worked in IE10, but didn’t work in FF and Chrome. So what’s the reason of this behavior?

First of all let’s check ULS (as always). In my case there were several interesting records:

QueryTemplateHelper: Query template '(PublishingDate=1/1/{QueryString.Year}..31/12/{QueryString.Year})' transformed to query text '(PublishingDate=1/1/2013..31/12/2013)'

It shows how query transformation component transformed the search query. In this example we use year specified in query string in order to show all news for specific year. Transformed query was the same for IE and FF, so the problem was somewhere else.

Next interesting line was:

ExecuteFlowInternal Flow:Microsoft.SharePointSearchProviderFlow Exception: Microsoft.Office.Server.Search.Query.QueryMalformedException: Query '(PublishingDate=1/1/2013..31/12/2013)' failed: syntax error at position 1, Unable to parse '31/12/2013' as an absolute datetime value

it appeared only in FF where query didn’t work. So the problem was in the datetime format: Sharepoint couldn’t parse datetime string in FF and Chrome. But why it happened? Very often such problems occur because of different locales used for parsing the string. I checked languages settings in IE10 (there is no separate setting for languages now in IE. It uses languages specified in OS) and FF: there was difference. In IE there was Russian and English (US) languages, while in FF there was only English (US). Accordingly in http requests fiddler showed the following Accept-Language headers in the browsers:

  • Accept-Language: ru,en-us – in IE
  • Accept-Language: en-us – in FF

When I added Russian language to FF, search queries started to work, but we couldn’t use this solution in production of course: site shouldn’t rely on the client’s browser language setting, it should work in all cases. So I started deeper investigation.

First of all in Sharepoint 2013 there is convenient way to test search queries from UI against particular search result source: go to Site settings > Search result sources > select appropriate result source and click Edit. Then click Launch query builder button:

image

In the opened window write your query and click Test query. Here is the result in FF:

image

If we will check what happens in fiddler when you click on the Test query button, we will find that Sharepoint makes request to the client object model end point to the following URL:

http://example.com//_vti_bin/client.svc/ProcessQuery

It returns response in JSON format. In case of FF it returned exception:

[
{
"SchemaVersion":"15.0.0.0","LibraryVersion":"15.0.4420.1017","ErrorInfo":null,"TraceCorrelationId":"9213339c-4c53-3023-9599-62e1b6279428"
},185,{
"IsNull":false
},193,{
"IsNull":false
},197,{
"IsNull":false
},205,{
"IsNull":false
},219,{
"IsNull":false
},220,{
"HasException":true,"ErrorInfo":{
"ErrorMessage":"We didn't understand your search terms. Make sure they're using proper syntax.","ErrorValue":null,"TraceCorrelationId":"9213339c-4c53-3023-9599-62e1b6279428","ErrorCode":-1,"ErrorTypeName":"Microsoft.Office.Server.Search.Query.QueryMalformedException"
}
}
]

And in IE it returned actual search results. I.e. it seems like that client object model uses browser language for some operations. For example it uses it for datetimes parsing when KQL contains datetimes. Don’t know why MS did it like this, but it often will be a problem because you don’t want to rely on client browsers settings, functionality should work regardless of it.

But how to fix the problem? First of all I tried different syntaxes for the range operator in KQL:

PublishingDate=1/1/2013..31/12/2013
PublishingDate=1.1.2013..31.12.2013
PublishingDate=1/1/2013..12/31/2013

All of them had similar problem: depend on the browser language. The I tried to add the following line to the web.config in order to disabled changing UI settings based on the browser language:

<globalization fileEncoding="utf-8" enableClientBasedCulture="false" />

(tried to change it both in site virtual folder and in 15\isapi folder which is mapped to _vti_bin virtual sub folder in Sharepoint sites).

I already started to think about hard fix: implement custom http module which will change Accept-Language header for requests to the client object model end point (client.svc), but then tried to use one more syntax for datetimes:

PublishingDate=2013/1/1..2013/12/31

And fortunately it worked regardless of the browser language:

image

When I changed the year in the query it correctly showed the news published in this changed year, so logic was correct.

Important summary from this post is that Sharepoint uses browser language settings in client object model which may lead to different problems. In the example above solution was quite easy and doesn’t have side effects which would affect other functionality, but it may appear in other cases. Notice it when you will work with search-driven sites in Sharepoint 2013.

Sunday, July 7, 2013

How to get friendly URL of the current page in Sharepoint programmatically

Friendly URLs is the new feature of Sharepoint 2013. It allows to show urls like http://example.com/products/ instead of http://example.com/products/pages/default.aspx in browser address bar, which is shorter and more user friendly. For developers it adds several challenges. I wrote about several of them already in the following posts (here, here and here). In web development in general it is often needed to get URL of the current page. When you use structural navigation and regular URLs it is quite easy:

   1: string url = HttpContext.Current.Request.Uri.OriginalString;

But how to get friendly URL of the current page when managed metadata navigation is used? The answer is TaxonomyNavigationContext class. It contains several properties which will help you to work with friendly URLs programmatically, e.g. HasFriendlyUrl and ResolvedDisplayUrl (all properties can be found here). Using this class you can get friendly URL using the following code:

   1: string url = "";
   2: if (TaxonomyNavigationContext.Current != null &&
   3:     TaxonomyNavigationContext.Current.HasFriendlyUrl)
   4: {
   5:     url = SPUtility.GetFullUrl(SPContext.Current.Site,
   6:         TaxonomyNavigationContext.Current.ResolvedDisplayUrl); 
   7: }

If you are on the page with real URL http://example.com/products-site/info-site/pages/default.aspx this code will return friendly URL (e.g. http://example.com/products/info) and you will be able to use it in your code.

Sunday, June 16, 2013

Support for IN CAML operation: Camlex 3.5 and Camlex.Client 1.3 are released

I have good news for Sharepoint developers who use Camlex in their project: I’ve released new versions of Camlex and Camlex.Client which now support IN operation (finally). At first I will show examples and describe some technical details and then add several notes about using of Camlex in different Sharepoint versions (2007, 2010 and 2013).

What is IN operation? As msdn article says:

Specifies whether the value of a list item for the field specified by the FieldRef element is equal to one of the values specified by the Values element.

E.g. if we need to get all list items which have integer Count field in range 0..9 we can use the following query:

   1: <Where>
   2:   <In>
   3:     <FieldRef Name="Count" />
   4:     <Values>
   5:       <Value Type="Integer">0</Value>
   6:       <Value Type="Integer">1</Value>
   7:       <Value Type="Integer">2</Value>
   8:       <Value Type="Integer">3</Value>
   9:       <Value Type="Integer">4</Value>
  10:       <Value Type="Integer">5</Value>
  11:       <Value Type="Integer">6</Value>
  12:       <Value Type="Integer">7</Value>
  13:       <Value Type="Integer">8</Value>
  14:       <Value Type="Integer">9</Value>
  15:     </Values>
  16:   </In>
  17: </Where>

It was possible to combine multiple Eq operations using Or and get the same result. And with Camlex it was quite easy to do it using single line of code (for better formatting I put it to 3 lines):

   1:  
   2:  
   3:  
   4: string caml = Camlex.Query().WhereAny(
   5:     Enumerable.Range(0, 9).Select<int, Expression<Func<SPListItem, bool>>>(
   6:         i => x => (int) x["Count"] == i)).ToString();

But let’s see the resulting CAML of the above code:

   1: <Where>
   2:   <Or>
   3:     <Or>
   4:       <Or>
   5:         <Or>
   6:           <Or>
   7:             <Or>
   8:               <Or>
   9:                 <Or>
  10:                   <Eq>
  11:                     <FieldRef Name="Count" />
  12:                     <Value Type="Integer">0</Value>
  13:                   </Eq>
  14:                   <Eq>
  15:                     <FieldRef Name="Count" />
  16:                     <Value Type="Integer">1</Value>
  17:                   </Eq>
  18:                 </Or>
  19:                 <Eq>
  20:                   <FieldRef Name="Count" />
  21:                   <Value Type="Integer">2</Value>
  22:                 </Eq>
  23:               </Or>
  24:               <Eq>
  25:                 <FieldRef Name="Count" />
  26:                 <Value Type="Integer">3</Value>
  27:               </Eq>
  28:             </Or>
  29:             <Eq>
  30:               <FieldRef Name="Count" />
  31:               <Value Type="Integer">4</Value>
  32:             </Eq>
  33:           </Or>
  34:           <Eq>
  35:             <FieldRef Name="Count" />
  36:             <Value Type="Integer">5</Value>
  37:           </Eq>
  38:         </Or>
  39:         <Eq>
  40:           <FieldRef Name="Count" />
  41:           <Value Type="Integer">6</Value>
  42:         </Eq>
  43:       </Or>
  44:       <Eq>
  45:         <FieldRef Name="Count" />
  46:         <Value Type="Integer">7</Value>
  47:       </Eq>
  48:     </Or>
  49:     <Eq>
  50:       <FieldRef Name="Count" />
  51:       <Value Type="Integer">8</Value>
  52:     </Eq>
  53:   </Or>
  54: </Where>

Comparing with 1st example, it looks not very nice. If it doesn’t matter for you, you still can use OR syntax. However now it is possible to write simpler expression which will produce IN syntax:

   1: string caml =
   2:     Camlex.Query().Where(x => Enumerable.Range(0, 9).Contains((int)x["Count"]))
   3:         .ToString();

It will produce CAML which we already saw:

   1: <Where>
   2:   <In>
   3:     <FieldRef Name="Count" />
   4:     <Values>
   5:       <Value Type="Integer">0</Value>
   6:       <Value Type="Integer">1</Value>
   7:       <Value Type="Integer">2</Value>
   8:       <Value Type="Integer">3</Value>
   9:       <Value Type="Integer">4</Value>
  10:       <Value Type="Integer">5</Value>
  11:       <Value Type="Integer">6</Value>
  12:       <Value Type="Integer">7</Value>
  13:       <Value Type="Integer">8</Value>
  14:     </Values>
  15:   </In>
  16: </Where>

For those who worked with NHibernate or Linq2Sql this syntax won’t be new: these ORM frameworks use the same syntax for generating of SQL queries with IN operator. I intentionally showed example with dynamically populated array (Enumerable.Range(0, 9)): code supports any expression which produces IEnumerable:

   1: var caml = Camlex.Query().Where(x => getArray().Contains((int)x["Count"])).ToString();
   2: ...
   3: List<int> getArray()
   4: {
   5:     var list = new List<int>();
   6:     for (int i = 0; i < 10; i++)
   7:     {
   8:         list.Add(i);
   9:     }
  10:     return list;
  11: }

(Do you see the difference between the last example which function which returns List<int>, and previous example, which uses IEnumerable? If yes, you know C# well :). Class List<T> has own Contains method, while for IEnumerable<int> from first example Linq Contains extension method was used. As you can see Camlex may work with both of them. Note that if you use Linq you should add “using System.Linq;” to your file).

I.e. basic syntax is the following:

   1: var caml = Camlex.Query().Where(x =>
   2:     enumerable.Contains((Type)x["FieldTitle"])).ToString();

Of course you may write array with constants:

   1: string c = Camlex.Query().Where(x => new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
   2:     .Contains((int) x["Count"])).ToString();

Also it will work with any type supported for Value element:

   1: string c = Camlex.Query().Where(x => new[]
   2:     {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
   3:         .Contains((string) x["Title"])).ToString();

It will produce the following result:

   1: <Where>
   2:   <In>
   3:     <FieldRef Name="Title" />
   4:     <Values>
   5:       <Value Type="Text">zero</Value>
   6:       <Value Type="Text">one</Value>
   7:       <Value Type="Text">two</Value>
   8:       <Value Type="Text">three</Value>
   9:       <Value Type="Text">four</Value>
  10:       <Value Type="Text">five</Value>
  11:       <Value Type="Text">six</Value>
  12:       <Value Type="Text">seven</Value>
  13:       <Value Type="Text">eight</Value>
  14:       <Value Type="Text">nine</Value>
  15:     </Values>
  16:   </In>
  17: </Where>

Now it uses Text type in Value elements.

That was only half of the story. If you follow the Camlex, you probably know that starting with version 3.0 it became bidirectional (I wrote about it here: Camlex.NET became bidirectional and goes online. Version 3.0 is released). So all conversions are added with 2 directions: from expression to CAML and from CAML to expression:

   1: var xml =
   2:     "<Query>" +
   3:     "  <Where>" +
   4:     "    <In>" +
   5:     "      <FieldRef Name=\"Title\" />" +
   6:     "      <Values>" +
   7:     "        <Value Type=\"Text\">zero</Value>" +
   8:     "        <Value Type=\"Text\">one</Value>" +
   9:     "        <Value Type=\"Text\">two</Value>" +
  10:     "        <Value Type=\"Text\">three</Value>" +
  11:     "        <Value Type=\"Text\">four</Value>" +
  12:     "        <Value Type=\"Text\">five</Value>" +
  13:     "        <Value Type=\"Text\">six</Value>" +
  14:     "        <Value Type=\"Text\">seven</Value>" +
  15:     "        <Value Type=\"Text\">eight</Value>" +
  16:     "        <Value Type=\"Text\">nine</Value>" +
  17:     "      </Values>" +
  18:     "    </In>" +
  19:     "  </Where>" +
  20:     "</Query>";
  21:  
  22: var expr = Camlex.QueryFromString(xml).ToExpression();

Applications of that feature:

1. on Camlex Online site add xml shown below to the textarea and click Convert to C#. It will show you how this query will be produced by Camlex:

   1: Camlex.Query().Where(x => new[] {
   2:     "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }
   3:         .Contains((string)x["Title"]))

2. it is possible to add more conditions to the existing IN query which is stored as xml, or add IN query to existing query:

   1: var xml =
   2:     "<Query>" +
   3:     "  <Where>" +
   4:     "    <In>" +
   5:     "      <FieldRef Name=\"Title\" />" +
   6:     "      <Values>" +
   7:     "        <Value Type=\"Text\">one</Value>" +
   8:     "        <Value Type=\"Text\">two</Value>" +
   9:     "      </Values>" +
  10:     "    </In>" +
  11:     "  </Where>" +
  12:     "</Query>";
  13:  
  14: string caml = Camlex.Query().WhereAll(xml, x => (int)x["Count"] == 1).ToString();

will produce:

   1: <Where>
   2:   <And>
   3:     <Eq>
   4:       <FieldRef Name="Count" />
   5:       <Value Type="Integer">1</Value>
   6:     </Eq>
   7:     <In>
   8:       <FieldRef Name="Title" />
   9:       <Values>
  10:         <Value Type="Text">one</Value>
  11:         <Value Type="Text">two</Value>
  12:       </Values>
  13:     </In>
  14:   </And>
  15: </Where>

I.e. Camlex may combine several string queries using Or and And, or even mix string query with expression as shown above. This feature was added in previous releases.

That was part with examples. Now about using of Camlex in different Sharepoint versions. Camlex was initially developed for Sharepoint 2007 and it references Microsoft.SharePoint.dll of 12.0.0.0 version (it only references it for compilation. Camlex doesn’t call any methods of Sharepoint API). However thanks to assemblies binding redirect in Sharepoint it works also in 2010 and 2013 (see this post for details why: Assembly binding redirect in Sharepoint 2010: how old code for SP 2007 works in SP 2010). IN CAML operation was introduced with Sharepoint 2010, i.e. it won’t work in Sharepoint 2007. So before to release new version 3.5 with IN operation support I choose between 2 options:

1. add it to existing Camlex and continue to use Microsoft.SharePoint.dll of 12.0.0.0 version.
Pros: one dll which works in all Sharepoint versions, it is simpler for developers who will want to install it.
Cons: IN element will be created now also for Sharepoint 2007, but it won’t work when try to execute this query against data.

2. create separate branch for Sharepoint 2007 and leave reference to 12.0.0.0 assembly only there, while in default branch change it to 14.0.0.0, so it will be used only starting with Sharepoint 2010, where IN operaion is supported.
Pros: each branch will have only supported features in appropriate version.
Cons: developers should choose correct version by themselves, codeplex is not very good in showing them, it is quite simple to get lost in releases there.

Also with 2nd option it would be necessary to maintain one more branch (currently there are 2 branches: default for basic Camlex and client branch for Camlex for client object model. BTW Camlex.Client.dll of version 1.3 supports IN operator as well). As currently I’m the only continuous contributor of the project and I have very limited time, I choose option 1 for now. May be in future I will separate branches, but for a while there will be single Camlex branch which will work with all Sharepoint versions, but generated CAML may not work in Sharepoint 2007.

With codeplex assemblies I also updated nuget packages. You can install latest versions by the following commands:

basic Camlex:

   1: Install-Package Camlex.NET.dll

for client object model:

   1: Install-Package Camlex.Client.dll

In my next plans to add rest of CAML elements introduced with Sharepoint 2010 (Include, NotInclude) and Joins. They also should be added of course at some point of course.