Sense/Net 6.0 Devblog
The development blog of Sense/Net 6.0
Back to Sense/Net

Efficient JSON communication in ASP.NET MVC

January 20, 2010 19:59 by Peter Zentai

A really short example on how ASP.NET MVC can be used for two-way JSON string communication.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using SenseNet.ContentRepository.Storage;
using SenseNet.ContentRepository.Storage.Security;
using System.Web.Script.Serialization;
using System.Runtime.Serialization.Json;

namespace SenseNet.Services.ContentStore
{
public class JsonFilter : ActionFilterAttribute
{
public string Param { get; set; }
public Type DataType { get; set; }

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(DataType);
var data = ser.ReadObject(filterContext.HttpContext.Request.InputStream);
filterContext.ActionParameters[Param] = data;

}
}
}
public class SecurityController : Controller
{

public ActionResult GetACL(string path)
{
var node = Node.LoadNode(path);
var acl = node.Security.GetAcl();
return Json(acl);
}

[AcceptVerbs(HttpVerbs.Post)]
[JsonFilter(DataType = typeof(SnAccessControlList), Param = "acl")]
public ActionResult SetACL(SnAccessControlList acl)
{
var node = Node.LoadNode(acl.Path);
node.Security.SetAcl(acl);
return null;
}
}

}

Tags:

Categories: .Net
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Searching a tree structure with Lucene.Net

December 16, 2009 03:00 by Peter Zentai

 

   1: /*
   2: Newsflash!
   3: 
   4: It’s now just a couple of days and we release Beta5. 
   5: In that the Content Query infrastructure is moved to the Lucene platform. 
   6: Sense/Net 6.0 endorses the eat your own dogfood philosophy, 
   7: so the Content Query feature is massively used across the system 
   8: in the core functionality. Even the repository type system 
   9: relies on the Content Query layer. 
  10: We expect a nice boost in the global system performance 
  11: in every content releated feature. Read on to find out why.
  12: */

Lucene is amazing – it is really everything you want from a software component: it’s smart, does it’s job well - asking very little in response, greatly simplifies your (professional) life :), open source (so you can feel more confident: you will have a higher success rate in mitigating project risks coming from relying on a 3rd party tool),  extensible and proven.

On our way to implement the Sense/Net Content Repository Lucene Adapter we had some experiences that worth sharing on using Lucene with deeply structured content and path based queries.

As Lucene follows a flat model (one and only one document type, arbitrary fields, no structures), the most trivial approach would be to flatten the tree by storing the position of each node as an extra stored/indexed field added to the node’s own fields– let call it the Path field.

The PrefixQuery

Now, finding nodes in a specific sub-tree looks really simple as we have PrefixQuery at hand:

private IEnumerable<DocumentWrapper> Search()
{
var pathquery = new PrefixQuery(new Term("Path", "c:\\Development"));
var result = Searcher.Search(pathquery);
foreach (Document o in result.Iterator)
{
yield return (new DocumentWrapper(o));
}
}

In your first couple of test scenarios it works nice. So you increase the size of your prototype to let’s say handle quarter a million of items now. Just to run into the the dreaded “TooManyClauses was unhandled” exception

image

It turns out the the PrefixQuery compiles into a list of possible TermQueries connected with OR relation, so basically the query Path = “C:\Development*” transforms into this: Path = “C:\Development\Folder1” OR Path = “C:\Development\Folder2” OR … and so on. The list is capped at 1023.

This 1023 limit looks really bad, but googling around the topic quickly brings up a solution that appears to be working.

The PrefixFilter solution!

The PrefixFilter let’s you efficiently filter rows from the query result based on a prefix criteria.

var query = new MatchAllDocsQuery();
var filter = new PrefixFilter(new Term("Path", "c:\\Development"));
var result = Searcher.Search(query, filter);

The query completes nicely, but with a touch of sluggishness. It has two major drawbacks however

- This approach splits the original query into two parts – a query and a filter, and it would complicate things to a level that would likely to be error prone in complex query cases (where multiple references of filters would be needed)

- Performance drops to mediocre/bad this way: in my test environment (Processor: Core2Duo, 2Ghz, Lucene index: 219000 rows, my complete c:'\ drive effectively) searching for c:\Development* returned 34.000 hits in 500 milliseconds. What is even worse: the execution time does not drop significantly as the result count get smaller. You may say: hey, 500 milliseconds is fantastic for such a mighty query!! yes. for the desktop it is… For the “Server Side”– it isn’t. In our case millions of queries will run a day, most of them around content pathes, and if each would cost us 500ms then we are – let’s face it - mucked.

So what else do we have?

The ConstantScoreQuery Solution?

The ConstantScoreQuery wraps a filter – a PrefixFilter in our case – and turns it into a Query class, ready to be combinef with other query parts. It removes the complexity of the split query model at least.

private IEnumerable<DocumentWrapper> Search()
{
var prefixFilter = new PrefixFilter(new Term("Path", "c:\\Development"));
var query = new ConstantScoreQuery(prefixFilter);
var result = Searcher.Search(query);
....
}

But

- The performance is even worse, 800 milliseconds now

- Plus now we need to give up ranking and scoring or at least we are threatened by constant scores instead of the default relevant scores.

And this is the point where we can be relatively sure that the problem lies in our approach and not in the implementation. Lets think in TERMS.

The Ancestors array property way

Instead of querying the Path field for a prefix match let’s extend our Lucene storage model. On the top of the path field let’s store each and every ancestor’s path of the node in the Ancestor array property.

 

private static Field[] CreateAncestorFields(string path, string separator)
{
string[] fragments = path.Split(new string[] { separator }, StringSplitOptions.None);
List<Field> fields = new List<Field>();
for(int i = 0; i < fragments.Length; i++)
{
string value = string.Join(separator, fragments, 0, i+1);
fields.Add(new Field("Ancestor", value, Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));
}
return fields.ToArray();
}

so:

the document at c:\development\sensenet\luceneadapter\program.cs will have 4 Ancestor fields, these:

c:\
c:\development
c:\development\sensenet
c:\development\sensenet\luceneadapter

Lucene thinks in TERMS. Each of the above lines became a TERM of its own, and when we search for contents with a specific term as a value for one of the content’s fields, then we are back in Lucene’s domain. A simple TermQuery to the Ancestor field will produce the desired result: in no time.
private IEnumerable<DocumentWrapper> Search()
{
var query = new TermQuery(new Term("Ancestor", "c:\\Development"));
var result = Searcher.Search(query);
....
}

 
 Capture
  Times are milliseconds.

 

And what is the trade here? Index gets bigger of course. For ~219K items this meant about 30 extra MBs. Compared to the total index size which is 1.6GB this tradeoff is acceptable. The memory footprint is small however: searching the index gobbled up only an additional 4MB of memory.

The sn:SenseNetDataSource is here!

December 1, 2009 19:25 by Peter Zentai

I am really excited to announce that today -as part of the Beta5 marching- we checked in the SenseNetDataSource feature.

With this new ASP.NET DataSource you can use the Sense/Net Content Repository with the rich set of DataBound controls  provided by Microsoft and other vendors (like GridView, ListView or Form) to produce more in less time using the data driven, rapid application development approach.

Also, the SenseNetDataSource (and some other controls I’ll tell you about later) makes it easier for you to build declarative solutions, that are easier to maintain, as much of the scenarios that in previous Betas needed coding now can be developed without a line of code – as long as we don’t consider writing html tags coding :).

So here is how it works: of course the way you expected it. You place a SenseNetDataSource object in the markup (you can do this from code of course) and link it to a DataBound control - GridView in our example.

image

The ContentPath attribute specifies the Content (typically a collection) we are interested in. MemberName is optional, and its default value is “Children” – so the default behavior is to list a content’s child items. You can also target reference properties with the MemberName attribute if the content has any (like “Related Articles” can be a reference property defined on an Article content type).

The result is as might expected to be:

image

Beyond accessing simple collections of the Content Repository, the SenseNetDataSource can also provide an easy access to the ContentQuery functionality. Setting the Filter, OrderBy and GroupBy attributes will help you to define your query expressions on an easy, declarative way.

But wait! Haven’t I seen Eval and BoundField there? So all these new stuff now needs C# classes and so? Do I have to define my content types in CODE NOW????

 

Wait, no! Not at all! Quite the contrary: the best thing is that all these data binding magic works with the Content Types you created as Content Types Definitions – mere XML data. This is a really really important thing: with Sense/Net 6.0 your are able to define data types – content types we call it – dynamically and then your are able to treat instances from them as strongly typed, bindable data entities.

Here is how it works:… But now I really must be going home :) I’ll finish this today, so stay tuned.

Raising the dead - How to find out what makes your website seemingly dead?

November 24, 2009 18:13 by Tamás Bíró

There are certain situations, when your website or web app stops responding. Your browser shows an hourglass, but your server load is never near 100%. What does you server do than?

Here is a short and easy way to find out what does your server do instead of serving up pages. More precisely, here is a way to find out where exactly your web app stops working.

We used this tool recently to find a hideous bug in a portlet. The portlet called a webservice, that was fast all the time, except in a few cases, where it did not respond within 60 seconds or more. This made the calling thread wait indefinitely, and when many such threads appeared, the whole thing hung. This usually happened after a few hours, depending on the number of visitors. The CPU was well under 10% on both the IIS and the SQL server. When we checked the site, everything was OK, but after a while, the thing hung and stopped responding until an app restart. Naturally, none of this happened on developer workstations, since there was no traffic on them, so the number of waiting threads never went high.

After using this tool, we found out about this, and it took only an hour to rewrite the portlet.

Here are six  easy steps to find out what hangs your server. Have fun!

Step #1
Install WinDbg on the production server:
32 bit: http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
63 bit: http://www.microsoft.com/whdc/devtools/debugging/install64bit.mspx

Step #2
Start WinDbg

Step #3
Attach WinDbg to a process, namely the W3WP process in case of web applications
File > Attach to a process > w3wp.exe

Step #4
You find yourself in the WinDbg console. The website is in suspend mode now, so act quickly.

Step #5
Type the following commands in the console input:
.loadby sos mscorwks [press enter]
~*e !clrstack [press enter]  This will show you which worker thread is in which .NET procedure

Step #6
Send the content of the screen to your developers for analysis. :-)

As an example, here is what a simple one-button ASPX page does when you make it sleep for 20 seconds in a simple Button1_Click event. As you can see from the screenshot, there are two requests that are “hung”, both of them in the Button1_Click procedure. 

Tags:

Categories: .Net | Documentation
Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

Sense/Net 6.0 Beta 3, Package installer and XSLT support

February 12, 2009 23:57 by Peter Zentai

The new Beta release is comencing. This part of a release phase I enjoy the best: the new features we planned for the release are rolling down from the assembly line each and every day. Pretty much an Xmas for a guy like me. The Beta 3 release aims two targets. Firstly we are planning to achieve a level of readyness able to serve a pruduction installation and as such is ready to be used in a commercial project. Secondly we are adding a couple of new features and modules that are a must in a real word portal building scenario. I'll be pleased to share the list of new features as the date of the next Beta is set.

Two particularly interesting pieces of this weeks goodies are the Package installer and the XSLT rendering support in the Sense/Net 6.0 portlets.

Package Installer  

The Package Installer as its name implies let's you pack your portal modul solution in an installable unit and upon installation deploys the items the new module requires. As we and hopefuly the community releases new functionality the Package Installer will be an essential tool in submitting and deploying reusable portal modules.

The Package Installer supports the following portal building items (bricks):

  • Content Views (ascx files)
  • Content Handlers (classes inside an assembly)
  • Content Type Definitions
  • Page Templates
  • Portlets (classes inside and assembly)
  • Assemblies
  • SQL state changers (sql scripts :))
  • and conventional portal content like files, folders and content meta files

The cool thing is that there is a number of way to create a package. If you are a VS2008 developer you can embed the deployable content in an assembly, place some attributes to define what to install and there you go. If you need more control, you can subclass the PackageInstaller class and override the necessary functions. Should you be someone not entirely living inside the VS2008 you can create packages from mere file system files and zipping them up into a file will be just as good provided you dont need the control over the installation process.

XSLT rendering support

Beyond default ASCX based view rendering XSLT can be used to handle complex display scenarios. Here you code the raw html output with the excellent capabilities of the XSLT language to transform XML data into custom html.

The Sense/Net 6.0 factory built modules will support custom XSLT transformations as views by providing the serialized xml version of the data returned by the portlet logic. XSLT transformations can be uploaded as simple files to the portal and later be used as conventional Content Views. Custom portlets can support XSLT rendering by overriding the PortletBase.GetModel() or the SerializeModel() functions.

 

Sense/Net adopts the CMIS standard - the first in .NET world

November 3, 2008 19:16 by Tamás Bíró

We have developed a CMIS draft implementation in Sense/Net 6.0 Beta 2, soon to be released. It is possibly the first .NET implementation, as all supporting companies except from Microsoft are JAVA based. It is surely the first open source implementation on the .Net platform.

What is CMIS? Quoting WikiPedia: “Content Management Interoperability Services (CMIS) is a proposed standard consisting of a set of Web services for sharing information among disparate content repositories that seeks to ensure interoperability for people and applications using multiple content repositories. EMC, IBM, Microsoft, Alfresco, Open Text, SAP and Oracle have joined forces to propose CMIS, the first Web services technical specification for exchanging content with and between Enterprise Content Management (ECM) systems. The proposed standard has been registered for public comment with OASIS. More specifically, Content Management Interoperability Services (CMIS) is a technical specification domain model (data and services) for interacting with an ECM repository via Web Services. It provides a content management domain-specific data model, a set of generic services that act on that data model and several protocol bindings for these services, including: SOAP and Representational State Transfer (REST)/(Atom).”

Since Sense/Net 6.0 is both an Enterprise Portal and an Enterprise Content Management System, with its own Content Repository, we wanted to showcase how easy it is to use the .NET platform, WCF and Sense/Net 6.0 to implement the standard.

Our demo is a two way implementation, because our content repository has a CMIS service interface and our portal has a CMIS client Webpart (portlet). So other CMIS clients can access our contents, but our portal can aggregate content from other CMIS compliant systems, such as next generation SharePoint, Alfresco and others.

We are also building an online CMIS demo, which is accessible from our website, but is under construction, so it might not work all the time. The demo features two CMIS webparts. One is able to navigate the content repository; the other is able to aggregate content from two sources that you can enter. The screenshot above is the CMIS test webpart, showing the PFS root contents. The services can also be accessed, just copy the URI-s from the input boxes. It even works with a simple browser, showing XML. There is no authentication, so no login is required. 

The source code will be available within a few days, please stay tuned. is available for download from http://www.sensenet.hu/download 

Read more about the proposed CMIS standard at OASIS: http://xml.coverpages.org/cmis.html#birohttp://xml.coverpages.org/ni2008-09-10-a.html

Sense/Net 6.0 architecture model

September 8, 2008 23:21 by Orosz Gergely

Update (2009.03.27): From Sense/Net 6.0 Beta 3 Portal File System (PFS) is called Sense/Net Content Repository (SNCR)

 

The following article is intended to give an insight on the structure of Sense/Net 6.0 focusing on object storage and management. This topic is a rather complex one, however, understanding this chapter is vital for efficiently working with objects stored in the Portal File System.

The architecture model

The Sense/Net 6.0 storage architecture consists of 4 separate layers.

More...

Finding a SharePoint alternative

August 18, 2008 18:06 by Tamás Bíró

I have just come across a blog post about Alfresco on CMS Watch. In his post Alan Pelz-Sharpe writes that Alfresco is more developer friendly, especially when you want to push SharePoint beyond its limits. I agree that it is easy to push MOSS to its limits, and also agree that there are certain hardships you have to face when you develop with MOSS. But I still can not see how a JAVA based product could be a real alternative. More...

PFS structure basics - for administrators and developers

July 31, 2008 09:48 by Orosz Gergely

Update (2009.03.27): PFS was renamed to Sense/Net Content Repository (SNCR) in Sense/Net 6.0

PFS - entities in a tree

As mentioned before in a PFS review entry the Portal File System is an essential repository where all kinds of entities –documents, contents, custom objects, system files, images, style sheets etc. – are stored.

For the administrator with the help of the Portal Explorer these objects can easily be administered. Editing, adding, deleting and moving these entities is incredibly simple and straightforward. At the same time for the developer the PFS is the tool that makes the definition and handling objects a real ease.

Objects within the PFS are stored in a tree which makes the backend of the portal both structured and easily administrable. It also forces developers to organize the data stored within – the PFS was not designed to store a large amount of unstructured information but instead to efficiently manage structured entities and connections between.

More...

Portlet adventures part I - say hello world

July 10, 2008 13:29 by Peter Zentai

This is the first in a series of posts on building custom portlets for the Sense/Net Portal Engine TNG. The good news is: it is as simple as it can be and all you have to do is to subclass from the SenseNet.PortalEngine.Portlet class, implement your custom portlet logic with C# code and then place yours assembly in the portal application assembly discovery path (for example the Bin folder). That's it. As for the bad news there is no bad news here as the Portal Engine TNG Portlet API is basically the ASP.NET WebPart framework, extended with some Portal Engine TNG specific services and tools to simplify development, deployment and maintainance of WebPart based applications.

In these documents it is assumed that you are new to both the WebPart and the Portal Engine TNG technology but you bear with at least a minimal understanding of the ASP.NET Custom Control concept.

So here are the steps for creating a portlet that can be placed on a portal page and will say "Hello World" to me.

More...

Bookmark and Share