May 14, 2014, 7:40 AM
Ext.net + Sharpkit
Hello
Sharpkit ( C# -> javascript tool) is pretty silent topic on this forum, I wonder if someone tried to use it in conjuction with Ext.net. In fact, for a while my way of thinking was "ExtJs+Sharpkit" or "Ext.net",so I would not wonder if I'm nearly first trying that. After few weeks of usage "Ext.net + sharpkit" it seems to be pretty powerfull combination for me, so I would like to share my experience and as well if hear any tips in case there is someone who tried that. Note that I'm not "javascript enemy", I'm fine with writing and maintaining js code. But even so the introducing sharpkit opened some nice ways. As well note that I have no relation to Sharpkit company and I was not given anything for writing this post from them.
So after spending some time in these forums, basic architecture of the application is like "single page app with as much stuff in javascript as possible,where server part providers just a data somehow processed on client side to user controls", single page really means one aspx file. In fact pretty similar to what I would do if I have just ExtJs. That means good-bye to direct events and using just directMethods. In short example
1) App Structure
OfficeEdit.ascx:
and the ascx is translated to javascript usign simple trick like
...
UserControl ctrl = (UserControl)LoadControl("~/OfficeEdit");
var jsConfig = ComponentLoader.ToConfig(ctrl, false);
scripts.AppendFormat("AMS.Data.scripts.{0} = {1};", "officeEdit", JSON.Serialize(jsConfig));
...
So to say above in few words - UI is created using ascx files UI behavior code in parent Ext javascript class, technically there is technological separation between user interface and its functionality.
2) Sharpkit to the game
So now sharpkit comes to game, it's place is to replace OfficeEdit.js with C# code. Furtunatelly there is relativelly nice support in sharpkit for ExtJS, so start is pretty straightfoward:
next overriding of the initComponent
a) see that base C# code is replaced by "ExtJs callparent", this is bit confusing and so far must be done, otherwise different js code would be generated
b) initializeControls is with underscore. Reason here is that all C# methods are generated as public ExtJs methods (see that in javascript snippet above most of "methods" are private). so the question is how to face that. Problem is that I'm not aware of any "official pattern" for private methods for ExtJS 4.x, so can hardly ask Sharpkit guys to support it somehow. This will change with ExtJs 5. But from the other side - does it really matter? Sharkit methods are called by C# code 99% of time, and here encaspulation is set of course checked properly
c) so far its impossible to write this._btnCancel.click += btnCancel_click
Good new is that it can be fixed in future as for custom controls (mean those I define myself) it is possible.
3) cancel click and custom event
cancel click does not do anything interesting then
so in C#
4) Initialize controls and As operator
5) Save implementation and Direct methods call
so I have the server method like (first improvement would be probably to use MVC controller but practically I didn't find any way how it would help)
a) OfficeEditDTO (means any dto used on both sides of game) is created in separate library and make available for sharpkit
(you can see that it is used in Sharkit code as well as on the server code)
so that way I get type safety for the direct method parameters
b) I need one "intermediate" class that would transform the js call. I was trying to play with attributes of direct method in order to generate right javascript originally, but as number of parameters is different in both methods I didn't find a way how to make it work. So I add this to the sharkit side of project
Having this class is little annoying overhead, but as long as I don't find better solution I think it could be generated during the build usign reflection from the directmethods
6) save_success handler and the "dummy" helpers
this is desired code:
in js I have:
7) summary:
- I have my views in ascx (the same could be done in razor or so, I just like ascx files, in fact more then sencha architect)
- I have me javascript code in C#, the only js code I wrote is in "dummy" class helpers
All the features like refactoring and so then works - intelisence, resharper etc - works like a charm.
Practically I don't see myself productivity dramaticlly changing ith sharpkit, at least not now. Using sharpkit is bit more verbose, so I'm writing more code then before. But the benefit I spot here is less time in silly js bugs as once C# become compilable the js is correct.
I was thinking to use ExtJs + Sharpkit + sencha architect before and in fact I did similar excercise with that combination like the one above. Of course that's powerfull combination too, but the problem with that is
a) bit harder to stick sharkit scripts to the code generated by architect, basically architect responsibility are just views that require inheritance, which require working with two tools and switching here and back (of course sometimes that could be considerable advantage depending on team structure) and later on picking the architect scipts somehow
b) Ext.net has bit more features then ExtJs and I was missing those
c) At the end of the day I didn't find mysef slower with UI in ascx
To be fair there are some disadvantages of using sharkit as well
a) It cost something ( for project I'm working on it's price does not worth mentioning but definitelly it's not free for commercial usage)
b) ExtJS wrapper was autogenerated and contains some bugs - for example Observable is interface (what?) and so
c) There are some pieces that is good to remember ( like As operator above), but definitelly learning curve here is significantly faster then for whole ExtJs
d) documentation of Sharpkit is pretty poor. Well - A lot of stuff is traightwofard, but some managers ( and not only them) does not tust to projects like that. In fact my impression is that whole Sharpkit project is managed by 1-2 people ( so will it silently disappear one day? who knows...)
Any comments welcome
Zdenek
Sharpkit ( C# -> javascript tool) is pretty silent topic on this forum, I wonder if someone tried to use it in conjuction with Ext.net. In fact, for a while my way of thinking was "ExtJs+Sharpkit" or "Ext.net",so I would not wonder if I'm nearly first trying that. After few weeks of usage "Ext.net + sharpkit" it seems to be pretty powerfull combination for me, so I would like to share my experience and as well if hear any tips in case there is someone who tried that. Note that I'm not "javascript enemy", I'm fine with writing and maintaining js code. But even so the introducing sharpkit opened some nice ways. As well note that I have no relation to Sharpkit company and I was not given anything for writing this post from them.
So after spending some time in these forums, basic architecture of the application is like "single page app with as much stuff in javascript as possible,where server part providers just a data somehow processed on client side to user controls", single page really means one aspx file. In fact pretty similar to what I would do if I have just ExtJs. That means good-bye to direct events and using just directMethods. In short example
1) App Structure
OfficeEdit.ascx:
<alc:CustomXTypeFormPanel runat="server" CustomInstanceOf="AMS.SharpKit.UserControls.DynamicControls.UserManagement.Maintenance.OfficeEdit">
<Items> <ext:Panel runat="server" Title="Basic Properties" Frame="true" MarginSpec="5" Width="350">
<LayoutConfig>
<ext:VBoxLayoutConfig />
</LayoutConfig>
<Items> <alc:TextFieldControl runat="server" ItemID="txtOfficeDesc" FieldLabel="Office" Width="340" AllowBlank="false"/>
</Items>
<Buttons>
<ext:Button runat="server" Text="Save" Icon="Disk" ItemID="btnSave"/>
</Buttons>
</ext:Panel>
</Items>
</alc:CustomXTypeFormPanel>
where CustomXTypeFormPanel is public class CustomXTypeFormPanel : FormPanel
{
public override string XType
{
get
{
if (string.IsNullOrEmpty(CustomXType))
return CustomInstanceOf.Replace(".", "_");
return CustomXType;
}
}
public string CustomXType { get; set; }
public string CustomInstanceOf { get; set; }
public override string InstanceOf
{
get
{
return CustomInstanceOf;
}
}
}
And OfficeEdit js Ext class is smth likeExt.define("AMS.SharpKit.UserControls.DynamicControls.UserManagement.Maintenance.OfficeEdit", (function () {
var publicInterface = {
extend: "Ext.form.Panel",
alias: "widget.AMS_SharpKit_UserControls_DynamicControls_UserManagement_Maintenance_OfficeEdit",
_txtOfficeDesc: null,
_btnSave: null,
_btnCancel: null,
initComponent: function (){
this.callParent(arguments);
initializeControls.call(this);
this._btnCancel.on("click", this.btnCancel_click, this);
this._btnSave.on("click", this.btnSave_click, this);
}
};
// private methods
function btnCancel_click: (){
this.fireEvent("tabClose", this);
this.destroy();
}
function initializeControls: (){
this._btnSave = this.down("#btnSave");
this._txtOfficeDesc = this.down("#txtOfficeDesc");
this._btnCancel = this.down("#btnCancel");
}
function btnSave_click(){
if (this.getForm().isValid() == false){
Ext.MessageBox.alert("Validation Failed", "Validation has failed, please correct highlighted fields");
return;
}
var dto = {
OfficeID: this._data.OfficeId,
OfficeDesc: this._txtOfficeDesc.getValue()
};
Ext.net.DirectMethods.UserManagement_SaveOffice.callAjax(dto, {
target: this,
success: this.save_success,
scope:this
});
}
...
return publicInterface;
})());
}
Note that callAjax is a simple javascript helper that shows "Show loading..." mask on target while ext request is executedand the ascx is translated to javascript usign simple trick like
...
UserControl ctrl = (UserControl)LoadControl("~/OfficeEdit");
var jsConfig = ComponentLoader.ToConfig(ctrl, false);
scripts.AppendFormat("AMS.Data.scripts.{0} = {1};", "officeEdit", JSON.Serialize(jsConfig));
...
So to say above in few words - UI is created using ascx files UI behavior code in parent Ext javascript class, technically there is technological separation between user interface and its functionality.
2) Sharpkit to the game
So now sharpkit comes to game, it's place is to replace OfficeEdit.js with C# code. Furtunatelly there is relativelly nice support in sharpkit for ExtJS, so start is pretty straightfoward:
[JsType(JsMode.ExtJs, InlineFields = true)]
public class UserEdit : Ext.form.Panel
{
public string alias = "widget.AMS_SharpKit_UserControls_DynamicControls_UserManagement_UserEdit";
}
note that InlineFields attribute is now the only way how to have alias generated on the right place in extjs class definition (and it's picked later on by ascx result code so we need it)next overriding of the initComponent
protected override void initComponent()
{
this.callParent(@arguments);
//base.initComponent();
_initializeControls();
this._btnCancel.on("click", new JsNativeAction(_btnCancel_click), this);
this._btnSave.on("click",new JsNativeAction(_btnSave_click),this);
}
There are few notes around thisa) see that base C# code is replaced by "ExtJs callparent", this is bit confusing and so far must be done, otherwise different js code would be generated
b) initializeControls is with underscore. Reason here is that all C# methods are generated as public ExtJs methods (see that in javascript snippet above most of "methods" are private). so the question is how to face that. Problem is that I'm not aware of any "official pattern" for private methods for ExtJS 4.x, so can hardly ask Sharpkit guys to support it somehow. This will change with ExtJs 5. But from the other side - does it really matter? Sharkit methods are called by C# code 99% of time, and here encaspulation is set of course checked properly
c) so far its impossible to write this._btnCancel.click += btnCancel_click
Good new is that it can be fixed in future as for custom controls (mean those I define myself) it is possible.
3) cancel click and custom event
cancel click does not do anything interesting then
private void _btnCancel_click() {
fireEvent("tabClose",this);
this.destroy();
}
the C# definition of the event is more interesting:public event JsNativeAction<UserEdit> tabClose
{
[JsMethod(Name = "on", InsertArg0 = "'tabClose'", InsertArg2 = "this", Export = false)] add
{
}
[JsMethod(Name = "un", InsertArg0 = "'tabClose'", Export = false)] remove
{
}
}
the attribute purpose here is to enable handling even in C# way while genereting code in "javascript way"so in C#
userEdit.tabClose += delegate(UserEdit edit)
{
edit.close();
};
results javascriptuserEdit.on('tabClose', function (edit){
edit.close();
}, this);
I think it's pretty nice demostration of Sharpkit power - it's not a just blind convertor from one laguage to another but allows plenty of customization.4) Initialize controls and As operator
private void _initializeControls()
{
_btnSave = this.down("#btnSave").As<Button>();
_txtOfficeDesc = this.down("#txtOfficeDesc").As<TextFieldControl>();
_btnCancel = this.down("#btnCancel").As<Button>();
}
You can see .As operator usage. In fact , nativelly I tried to use cast operator, which does not work (at least generated some strange javascript). Simply answer to all the problems is "use AS" operator when chaning type in Sharpkit. that's one of things to remember)5) Save implementation and Direct methods call
private void btnSave_click()
{
if (this.getForm().isValid() == false)
{
Ext.MessageBox.alert("Validation Failed", "Validation has failed, please correct highlighted fields");
return;
}
var dto = new OfficeEditDTO
{
OfficeID = _data.OfficeId,
OfficeDesc = _txtOfficeDesc.text
};
/*
here I want to have :
Ext.net.DirectMethods.UserManagement_SaveOffice.callAjax(dto, {
target: this,
success: this.save_success,
scope:this
});
*/
}
Begining of method is pretty straigfoward, now the question is what to do with direct methods. Here maybe some of you give me better ideas as my solution is bit ... crazyso I have the server method like (first improvement would be probably to use MVC controller but practically I didn't find any way how it would help)
[DirectMethod(RethrowException = true)]
public static int UserManagement_SaveOffice(OfficeEditDTO dto)
{ return ServiceLocator.Get<UserManagementMaintenance>().SaveOffice(dto);
}
and on Sharpkit I would like to call it asOfficeEditDTO dto = ...
UserManagementDirectMethods.SaveOffice(dto, new AjaxParameter<int>
{
target = this,
success = save_success
});
and in javascript generated as Ext.net.DirectMethods.UserManagement_SaveOffice.callAjax(dto, {
target: this,
success: this.save_success,
scope:this
});
relativelly confusing task, here is my solutiona) OfficeEditDTO (means any dto used on both sides of game) is created in separate library and make available for sharpkit
(you can see that it is used in Sharkit code as well as on the server code)
[JsType(JsMode.Json)]
public class OfficeEditDTO
{
public int? OfficeID { get; set; }
public string OfficeDesc { get; set; }
}
It's marked as JSON type as that the way how Sharkit does not generate getter and setter when setting/getting it's propertiesso that way I get type safety for the direct method parameters
b) I need one "intermediate" class that would transform the js call. I was trying to play with attributes of direct method in order to generate right javascript originally, but as number of parameters is different in both methods I didn't find a way how to make it work. So I add this to the sharkit side of project
[JsType(JsMode.Json)]
public class AjaxParameter
{
public JsAction success { get; set; }
public Object target { get; set; }
}
[JsType(JsMode.Prototype, Name = "Ext.net.DirectMethods", Export = false)]
public class UserManagementDirectMethods
{
[JsMethod(Name = "UserManagement_SaveOffice.callAjax")]
public static int SaveOffice(OfficeEditDTO dto, AjaxParameter<int> args = null)
{
return 0;
}
}
See again that Export=false + Name attribute do the trick how to achieve desired code.Having this class is little annoying overhead, but as long as I don't find better solution I think it could be generated during the build usign reflection from the directmethods
6) save_success handler and the "dummy" helpers
this is desired code:
Ext.net.Notification.show({
iconCls: 'icon-information',
pinEvent: 'click',
html: 'Save done',
hideDelay: 5000,
title: title
});
obviously there is a problem - Sharpkit support so far ExtJs, not Ext.net. Sittindg down and writing a support for ext.nt is probably not the fastest idea, so "kind of dummy" classes comes into the gamein js I have:
AMS.Helpers = function () {
function showAMSTip(title, msg) {
Ext.net.Notification.show({
iconCls: 'icon-information',
pinEvent: 'click',
html: msg,
hideDelay: 5000,
title: title
});
}
on sharpkit then [JsType(JsMode.Prototype,Name="helpers", Export = false)]
public static class helpers
{
public static void showAMSTip(string title, string message){}
}
which as a result allows me to write private void save_success(int officeId)
{
helpers.showAMSTip("Save Succesfull", string.Format("Office {0} has been saved", _txtOfficeDesc.text));
}
pretty nice no? So far this trick worked for any "missing" functionality in Sharkpit and even more it forced me to extract the pieces I really need to helper methods. Note that I was given source code of sharpkit SDK, so I can really modify that and add Ext.Net support.7) summary:
- I have my views in ascx (the same could be done in razor or so, I just like ascx files, in fact more then sencha architect)
- I have me javascript code in C#, the only js code I wrote is in "dummy" class helpers
All the features like refactoring and so then works - intelisence, resharper etc - works like a charm.
Practically I don't see myself productivity dramaticlly changing ith sharpkit, at least not now. Using sharpkit is bit more verbose, so I'm writing more code then before. But the benefit I spot here is less time in silly js bugs as once C# become compilable the js is correct.
I was thinking to use ExtJs + Sharpkit + sencha architect before and in fact I did similar excercise with that combination like the one above. Of course that's powerfull combination too, but the problem with that is
a) bit harder to stick sharkit scripts to the code generated by architect, basically architect responsibility are just views that require inheritance, which require working with two tools and switching here and back (of course sometimes that could be considerable advantage depending on team structure) and later on picking the architect scipts somehow
b) Ext.net has bit more features then ExtJs and I was missing those
c) At the end of the day I didn't find mysef slower with UI in ascx
To be fair there are some disadvantages of using sharkit as well
a) It cost something ( for project I'm working on it's price does not worth mentioning but definitelly it's not free for commercial usage)
b) ExtJS wrapper was autogenerated and contains some bugs - for example Observable is interface (what?) and so
c) There are some pieces that is good to remember ( like As operator above), but definitelly learning curve here is significantly faster then for whole ExtJs
d) documentation of Sharpkit is pretty poor. Well - A lot of stuff is traightwofard, but some managers ( and not only them) does not tust to projects like that. In fact my impression is that whole Sharpkit project is managed by 1-2 people ( so will it silently disappear one day? who knows...)
Any comments welcome
Zdenek