Problem
How to get list of unique text values from XML document, for example to build a kind of dictionary from these node values.

Solution
nodename is name of node to select from.
preceding axis get everything what is before start tag of selected node.
It is also possible to use following axis to get everything what follows current node, with this axis, XPath will return results in reversed order

Code snippets

//nodename[not(.=preceding::text())]/text()

or

//nodename[not(.= following::text())]/text()

LotusDomino views and JSON

This gonna be really short post.

It is easy to obtain data from view as XML string, but to get this data as JSON it seems to be hard work.... not exactly :) I have just found really usefull parameter called Outputformat where we can set value JSON.

Here is how does it look:
http://<your server here>/<your data base here>.nsf/<your view here>?ReadViewEntries&Outputformat=JSON

Introduction


In last article I showed how easy is access to .NET WebService from ExtJS JavaScript Library. This solution has one big disadvantage. Due to security reasons HTTPRequest method used for performing AJAX calls is restricted to in-domain calls only. What in the case if our WebService is located on different machine and different domain? You will find answer for this question in this article.


Solution


As I mentioned before it impossible to access data located in different domain using HTTPRequest method, but we can use some trick. It is possible, using JavaScript to add any html tag to current document - even SCRIPT tag. As all we know SCRIPT tag allows to include JavaScript code into document and also SCRIPT tag can have URL where JavaScript code is located. This is not limited to the same domain, like in HTTPRequest case. Let's imagine that our source code in this case is remotelly and dynamically produced data returned as valid JavaScript code. When document is ready, we can acces this data and that's all. There 2 drawbacks of this solution. Performace is slightly worse (we need to call some remote domain, etc) and we have to prepare server side to handle script-tag requests. On ExtJS side we can just use ScriptTagProxy object class instead of regular HttpProxy.


Let's take data from last article:



{ "d": [{"AgentID": 1, "FirstName": "Jelena", "LastName": "Akerhus"},{"AgentID": 2, "FirstName": "Londo", "LastName": "Molari"}]}

To make it to work with ExtJS ScriptTagProxy class we need to return data in format like this:



stcCallback001({ "d": [{"AgentID": 1, "FirstName": "Jelena", "LastName": "Akerhus"},{"AgentID": 2, "FirstName": "Londo", "LastName": "Molari"}]});

Hey, does it look like JavaScript function call with our data provided as parameter? Yes exactly! Name for callback function is provided by ScriptTagProxy class as parameter added to URL. Default name for this callback is... callback. URL to acces remote data source will look like this:


http://your-remoted-domain/ScriptTagProxyHandler?callback=stcCallback001


ScriptTagProxy will do the job to extract data and put it into the store. All we need is to specify ScriptTagProxy instead of HttpProxy. Let's take code from last article and change proxy.



var store = new Ext.data.JsonStore({
autoLoad: true,
proxy: new Ext.data.ScriptTagProxy({
url: 'http://your-remote-domain/ScriptTagProxyHandler',
}),
root: 'd',
id: 'Id',
fields: ['Id', 'FirstName', 'LastName', 'BirthDate']
});

Now we need figure out how can we make our web service work with ScriptTagProxy. It could be easilly achieved with solution called PageProxy. What is PageProxy? In simple words: this is an aspx web page wich will receive all requests, and using reflection forward them to web service, then it will get back the response, enclousure with javascript callback function and forward it to request's sender.


Create aspx page and put this code there:



public partial class SimpleScriptPageProxy : Page
{
protected void Page_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
string result = "";
string callback = "";

try
{
// Get method name in web service GET call format
string methodName = Request.PathInfo.Replace("/", "");
// Get name of callback function
callback = Request["callback"].ToString();

// Invoke web service method and serialize response to json
// !Important!: Service is type of our web service
result = jsonSerialize(invokeMethod(typeof(Service), methodName));
}
catch (Exception ex)
{
result = jsonSerialize(ex); // When somethig wrong happens, just return exception serialized to json
}
// Prepare and send back response
sb.AppendFormat("{0}({{ d: {1} }});", callback, result);
Response.Write(sb.ToString());

}

/// <summary>
/// This method invokes fn method on type Type and returns answer.
/// </summary>
/// <param name="type">Type of class with method</param>
/// <param name="fn">Function name</param>
/// <returns>Method result</returns>
private object invokeMethod(Type type, string fn)
{
object result;
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod(fn);
ParameterInfo[] parameters = method.GetParameters();

if (parameters.Length == 0)
{
result = method.Invoke(instance, null);
}
else
{
List<string> paramValues = new List<string>();
for (int i = 0; parameters.Length > i; i++)
{
string paramName = parameters[i].Name;
string paramValue = Request[paramName]; // Get parameters directly from Request object

paramValues.Add(paramValue);
}
result = method.Invoke(instance, paramValues.ToArray());
}
return result;
}

// Helper method for json serialization
private string jsonSerialize(object o)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(o);
}
}

Set url to this web page in ScriptTagProxy and that's all. If You like to send any parameters to web service You can send them with request using GET or POST methods.

ExtJS and .NET WebServices

Introduction

ExtJS is very powerful JavaScript library, perfect for creating rich graphical user interface in web browser. You can make applications of many purposes and integrate data from many sources and technologies using XML, JSON or own interchange format. On the other hand .NET provides great server side features like entity framework, Linq and many more powerful classes. In this article I would like to show You how to integrate both technologies in the most convenient way and use strengths from both of them.

Solution

When You are trying to access different data sources on different servers, the best way in today's world is to use web services. In this way You can build SOA solution, accessible by many suppliers using different technologies. When we have decided to use ExtJS as GUI part and ASP.NET as server part, it would be ideally to use ASP.NET web services directly. Natively ExtJS does not support SOAP XML data source. You can write own data proxy if You like, but I will show You that it is not necessary. ASP.NET webservices, starting from version 2.0 allows You to talk in JSON format instead of SOAP XML.

Like in most cases, when You want to configure behavior of .NET classes You can use attributes. In this we need to decorate web service class with ScriptService attribute (form System.Web.Script.Services namespace), and then decorate methods with ScriptMethod attribute. Class attribute does not need any configuration, but we have to add some to method decorator also. All we need to specify is method response format, in this case ResponseFormat=ResponseFormat.Json and allow to talk to web service method using GET HTTP method. That is all we need on server side, let's go then to GUI part.


// Entity class declaration
public class Agent {
private int _agentID;
public int AgentID { get { return _agentID; } set { _agentID = value; } }
private string _firstName;
public string FirstName { get { return _firstName; } set { _firstName= value; } }
private string _lastName;
public string LastName { get { return _lastName; } set { _lastName= value; } }

public Agent() {}
public Agent(int agentID, string firstName, string lastName) {
_agentID = agentID;
_firstName= firstName;
_lastName= lastName;
}
}

...

// WebService declaration
[ScriptService]
public class Service : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true, XmlSerializeString = false)]
public List<Agent> GetAgents() {
List<Agent> agents = new List<Agent>();
agents.Add( new Agent('1', 'Jelena', 'Akerhus') );
agents.Add( new Agent('2', 'Londo', 'Molari') );

return agents;
}
}


This WebService will produce data structure looking like this:

{ "d": [{"AgentID": 1, "FirstName": "Jelena", "LastName": "Akerhus"},{"AgentID": 2, "FirstName": "Londo", "LastName": "Molari"}]}


We can access this data using json enabled data store in ExtJS, called Ext.data.JsonStore:

// Create store
var myStore = new Ext.data.JsonStore({
// Load data at once
autoLoad: true,
// Override default http proxy settings
proxy: new Ext.data.HttpProxy({
// Call web service method using GET syntax
url: 'Service.asmx/GetAgents',
// Ask for Json response
headers: {'Content-type': 'application/json'}
}),
// Root variable
root: 'd',
// Record identifier
id: 'AgentID',
// Fields declaration
fields: ['AgentID', 'FirstName', 'LastName']
});


And show obtained information using data grid:

var grid = new Ext.grid.GridPanel({
// Set store
store: myStore,
// Columns definition
columns: [
{ dataIndex: 'AgentID' },
{ dataIndex: 'FirstName' },
{ dataIndex: 'LastName' }
],
// Render grid to dom elemnent with id set to panel
renderTo: 'panel'
});

In this scenario we have obtained data from ASP.NET WebService and show it in ExtJS data grid. This approach has one big disadvantage: WebService have to be located within the same domain. In the next article I will show You how to perform Cross domain call from ExtJS to ASP.NET web service in simple steps.

Problem
While using Ext.ux.Chart.OFC.Panel I have encountered problems with statically delivered data (from js). I made panel embedding ofc panel, and I have created ofc panel in the simplest way (in my opinion):


this.chart = new Ext.ux.Chart.OFC.Panel ({
chartURL: 'shared/open-flash-chart/open-flash-chart.swf',
width: this.width,
height: this.height,
ofcCfg:{
autoSize : true
},
chartData: this.data
});


Ok, it works perfectly in FF but IE cries with #2032 error from OFC - which means no data to load was found. I have spent some time on reading forums (ExtJS, OFC) but without luck.

Solution
Finally while experimenting/debugging (PITA factor for IE is high here) I found finally two solutions:

1. You can extend ofc panel config by adding mediaMask="Whatever" and autoMask = true, loadMask is optional in this case:

mediaMask: 'Loading chart...',
autoMask: true,


2. Your can add random value to URL pointing to SWF file

chartURL: 'shared/open-flash-chart/open-flash-chart.swf?r='+Math.random(),


Hopefully it will save someone's plenty of time.

Remarks
Open Flash Chart is open source LGPL licenced flash chart component.

Ext.ux.Chart is part of Ext.ux.Media developed by Active Group and licenced under GPL3 licence.

When You will try to perform remote call to WebService made in Lotus Domino with access allowed only for authenticated users You will get login screen as an response. It is possible to disable this feature by setting "allow public access" true on WebService design element, but for security reasons it is not recommended. It is possible to send authentication information using two scenarios: Basic Authentication and Cookie Based Authentication.

Basic Authentication
This scenario is quite easy. It requires Internet access in Domino set to Basic Authentication.


// Create WebService proxy class instance
WebReference.WebServiceTestService service = new ConnectDominoWSTest.WebReference.WebServiceTestService();
// Enable pre-authentication
service.PreAuthenticate = true;
// Allow redirection (domino will redirect to logon screen and back to web service)
service.AllowAutoRedirect = true;
// Setting up credentials
service.Credentials = new NetworkCredential("YourUsername", "YourPassword");
// Perform Webservice call
string s = service.HELLOWORLD();


Cookie Based Authentication
Second scenario is more complicated, but thanks to .NET power it is possible to do. It requires Internet access in Domino set to Session-based authentication or Single sign-on.


// Cookie container to store authentication cookie
CookieContainer cookies = new CookieContainer();

// Prepare HTTP request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("YourServer/names.nsf?login");
request.Method = "POST";
request.AllowAutoRedirect = false;
request.ContentType = "application/x-www-form-urlencoded";
request.CookieContainer = cookies;

// Prepare POST body
string post = "Username=YourUsername&Password=YourPassword";
byte[] bytes = Encoding.ASCII.GetBytes(post);

// Write data to request
request.ContentLength = bytes.Length;
Stream streamOut = request.GetRequestStream();
streamOut.Write(bytes, 0, bytes.Length);
streamOut.Close();

// Get response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

// Check if we are authenticated properly
if ((response.StatusCode == HttpStatusCode.Found) ||
(response.StatusCode == HttpStatusCode.Redirect) ||
(response.StatusCode == HttpStatusCode.Moved) ||
(response.StatusCode == HttpStatusCode.MovedPermanently)) {

// Create WebService proxy class instance
WebReference.WebServiceTestService service = new ConnectDominoWSTest.WebReference.WebServiceTestService();
// Set up authentication cookie
service.CookieContainer = cookies;
// Perform Webservice call
string s = service.HELLOWORLD();
}


In both scenarios it is used WebService proxy class generated from wsdl file.

Normally if You declare store in ExtJS the default HTTP method is POST. Sometimes You need send data using GET method, so ExtJS is fortunatelly flexible enough to make it possible. You'll just need to create You own HttpProxy and change this proxy method to GET.

Default way using POST method:


var securities = new Ext.data.JsonStore({
url: 'some url...',
root: 'some json root...',
fields: [some fields...]
});


Store settings medified to send data using GET method:

var securities = new Ext.data.JsonStore({
proxy: new Ext.data.HttpProxy({url: 'some url...', method: 'GET'}),
root: 'some json root...',
fields: [some fields...]
});

Older Posts