Who is Ali Özgür?

RecentComments

Comment RSS

Posted in: Android , Mobile  Tags:
aliozgur posted on May 13, 2010 09:11

Intro

I've been recently working on a smart client (WinForms) application backed by Entitiy Framework 4 (EF4) on Visual Studio 2010. In this blog post I will try to give you some tips regarding some limitations and points to be careful about EF4.

Why Entity Framework (EF)?

Through my .NET development career I've used couple of ORM frameworks like NHibernate, LLBLGen and Subsonic. Each framework has some sort of unique approach to ORM. My favourite ORM was, and actually still is, NHibernate. I like the open source nature of NH and the community of NH is very active. LLBLGen was my second popular ORM because the tooling was inplace and entity mappings could be handled easly. Subsonic was minimalist and it was really a joy to develop with Subsonic. But each of these ORM frameworks made me crazy from time to time. To name few of them; configuring NHibernate is really a pain although they have some addins, LLBLGen has some sort of too imperative query constructs and Subsonic is minimalist and sometimes does not fit well while implementing some not so important part (classic %20 part) of a system. Oh I've forgot to mention LinqToSql which was the first shot of Microsoft in the ORM area. I've also used LinqToSql. 

Since EF was first announced I've been watching the progress and keep an eye on the experience of people using early EF versions. My first impression was; stay away until next major release. And that major release seems to be EF4. My answer to the question why EF is

  • EF4 comes as part of  .NET Framework 4. No extra installation needed
  • EF4 is fully integrated with Visual Studio 2010
  • EF4 Model Designer, incorperated in VS 2010 is nearly fantastic
  • With EF4 you can persist POCO's to supported databases easly
  • With EF4 you can generate your entities from your database schema
  • Complex Types are fancy
  • Function exports (stored procedure support) just work like a charm. Paired with complex types this introduces a real power for brown field projects

 

Change EF Connection String At Runtime

EF4 connection strings are different than usual Sql connection strings. Within EF4 connection string some sort of metadata regarding EF model resources shall be included so that EF can resolve the model and apply the mappings and other stuff you implicitly introduced through the Model Designer. In web application scenarios you likely will not have to worry about changing EF connection string at runtime since Model Designer asks you whether you want to persist the selected connection information in the config file. After that you simply change the sql connection information before you deploy your web app. But in smart client scenarios this technique does not fit well, since you do not want to expose database connection information in the app.config file. Most likely you will keep database connection information in a user specific setting file with some encryption applied since you do not want it to be human readable and when your application is up you will read that information, decode the connection string and use that value to issue a database connection.

Here is a typical Model Designer generated EF connection string

<add name="eXpressOtoEntities" connectionString="metadata=res://*/eXpressOtoEntities.csdl|res://*/eXpressOtoEntities.ssdl|res://*/eXpressOtoEntities.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=D00450065;Initial Catalog=eXpressOto;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

You have to construct a connection string similar to the one above, for practical purposes you can define a factory method which constructs an EF Connection String ans instantiates an ObjectContext for you. Here is the sample method

 public static eXpressOtoEntities CreateObjectContext()
{
if (DbConnectionManager.Current == null)
throw new Exception("Current database connection is not set on DbConnectionManager");

string conStr = "metadata=res://*;provider=System.Data.SqlClient;provider connection string='" + DbConnectionManager.Current.ConnectionString + "'";
eXpressOtoEntities ctx = new eXpressOtoEntities(conStr);
return ctx;
}

In the above code snippet eXpressOtoEntities, the return type of the method, is my ObjectContext class. DbConnectionManager is a custom static class which is used to encrypt/store, load/decrypt the database connection string. The rest is straight we just perform simple string concat.

Implementing IDataErrorInfo on your entities

IDataErrorInfo interface is a standard .NET interface residing in System.ComponentModel namespace which provides the functionality to offer custom error information that a user interface can bind to. Most of the WinForms controls, standard or third party, support IDataErrorInfo internally or through the standard .NET ErrorProvider component. If you want to provide error information to the end users regarding any kind of validation directly from the entities layer you just have to implement IDataErrorInfo on your entities, which is simple enough.

EF4 uses T4 templates to generate your entity classes from your model. When you add an entity to your model from your database schema EF runtime, VS2010 actually, uses predefined T4 templates to generate the corresponding entity classes. There are two different ways, as far as I know, you can add extra functionality to your EF entity classes.

1) You can create your own T4 template incorporating IDataErrorInfo and generating default implementation of the interface and feed the EF runtime with this template. This is a little bit complicated issue and I can ensure you that you would not want to enter that process just to have entities supporting IDataErrorInfo. You can read this post for the details.

2) Standard EF T4 template generate partial classes for your entities. Which means you can add functionality to your automatically generated entity classes by simply creating a partial class file. This approach is simple and sufficint for most of the time. Below is a sample partial entity class with IDataErrorInfo implementation

 
partial class ProjectType : IDataErrorInfo
{

#region IDataErrorInfo Members

public string Error
{
get
{
StringBuilder sb = new StringBuilder();

if (!String.IsNullOrWhiteSpace(this["Name"]))
sb.AppendLine(this["Name"]);

if (!String.IsNullOrWhiteSpace(this["Prefix"]))
sb.AppendLine(this["Prefix"]);

string errors = sb.ToString();
return !String.IsNullOrEmpty(errors) ? errors : String.Empty;
}
}

public string this[string columnName]
{
get
{
switch (columnName)
{
case "Name":
return String.IsNullOrWhiteSpace(Name) ? "Name can not be empty" : String.Empty;
case "Prefix":
return String.IsNullOrWhiteSpace(Prefix) ? "Prefixcan not be empty" : String.Empty;
default:
return String.Empty;
}
}
}

#endregion
}

The sample class above adds IDataErrorInfo implementation to my auto generated ProjectType entity class and is used to check if required fields Name and Prefix have values. That is it.

Handling General Definition Data

Nearly every system needs some sort of general definition data during operation. For example all web sites which require registration ask for country which is a general definition data. Most of the time that sort of data does not need extra or complex processing, this data is not at the core of the operation, but may be a core part in BI. System admins just define the data and the applications display that data to the end user. Schema of that sort of data is very simple just and Id and a Name field is enough, sometimes a description field can also be included. In our project we generalized that sort of data to include Id, Name and Active fields and defined a table for each type. May be we could handle this sort of data with a single table on the database side and utilize an inheritance strategy on the EF side. But for simplicity we just decided to discard this possibility.

We decided to provide a unified editor to the admins so that they can manipulate definition data. We designed the editor to operate with interfaces so that we can handle any general data definition entity implementing a contract, in a way some sort of data contract. Lets walk through the process step by step and give some code

Step-1: Define the data contract, that is IDefinitionDataEntity interface

public interface IDefinitionDataEntity
{
Int32 Id { get; set; }
string Name { get; set; }
bool Active { get; set; }
}

This is simple we just define an data contract defining the structure of our general data.

Step-2: Mark definition data entities with IDefinitionDataEntity interface

  [Description("Vehicle Kinds")]
partial class VehicleKind: IDefinitionDataEntity
{
}

We just define a partial class for our VehicleKind entity class, which was automatically generated by EF. Since our database schema contains Id, Name and Active columns actually EF generated VehicleKind class already contains these properties and we just simply mark our partial class with IDefinitionDataEntity.

NOTE: Description attribute is a standard .NET framework attribute which resides in System.ComponentModel namespace. We will use this attribute to render user friendly entity information in our data editor.

Step-3: Get all entity types implementing the IDefinitionDataEntity interface with reflection

public class DefinitionDataEntityTypeInfo
{
public Type EntityType { get; set; }
public string Description { get; set; }
public static ReadOnlyCollection<DefinitionDataEntityTypeInfo> TypeInfos
{
get;
private set;
}
static DefinitionDataEntityTypeInfo()
{
PrepareTypeInfos();
}
}

DefinitionDataEntityTypeInfo class is just a helper class which will be used to hold the information about the definition data entity classes which is populated through reflection. TypeInfos is where we hold the data for all definition entities. 

private static void PrepareTypeInfos()
{
Type tt = typeof(IDefinitionDataEntity);

var results = (
from a in
( from type in Assembly.GetExecutingAssembly().GetTypes()
where type.GetInterface(tt.FullName, true) != null
select type
)
where a.IsClass == true
select new DefinitionDataEntityTypeInfo { EntityType = a}
).ToList<DefinitionDataEntityTypeInfo>();

results.ForEach
(
delegate(DefinitionDataEntityTypeInfo t)
{
var z = (from x in t.EntityType.GetCustomAttributes(typeof(DescriptionAttribute),false)
select (DescriptionAttribute)x).FirstOrDefault < DescriptionAttribute>();
if (z != null)
t.Description = z.Description;
}
);

TypeInfos = results.AsReadOnly();
}

PrepareTypeInfos static method of DefinitionDataEntityTypeInfo class is called inside the static constructor and simply inspects all entity classes implementing IDefinitionDataEntity interface
and stores the inspection data to TypeInfos static property. 

Step-4: Get entity set name for of a definition entity type

In order to query and modify data we must have strongly typed entity sets for our definition entity classes or inspect the name of the entity set for each entity type inside our object context. To meet this requirement we create a partial class for our ObjectContext implementation and introduce tqo methods for our purpose; GetEntitySet and GetEntitySetName. Here is the implementation

partial class eXpressOtoEntities
{
// .....
// Some other stuff here
// .....

public EntitySetBase GetEntitySet(Type entityType)
{
EntityContainer container = this.MetadataWorkspace.GetEntityContainer(this.DefaultContainerName, DataSpace.CSpace);
EntitySetBase entitySet = container.BaseEntitySets.Where(item => item.ElementType.Name.Equals(entityType.Name))
.FirstOrDefault();

return entitySet;
}

public string GetEntitySetName(Type entityType)
{
EntitySetBase esb = GetEntitySet(entityType);
return esb != null ? esb.Name : String.Empty;
}
}

We use the metadata, actually included in the automatically generated EDM, attached to our ObjectContext implementation (eXpressOtoEntities) to inspect the entity set name for a specific definition entity type.

NOTE: Methods introduced here can be used to get entity set or entity set name of any EF entity class as well.

Step-5: Load definition data

The final step is loading the our strongly typed definition data inside our unified editor based on the user selection. Here is the code.

private void LoadData(Type entityType)
{
ObjectQuery<IDefinitionDataEntity> qry = _ctx.CreateQuery<IDefinitionDataEntity>(String.Format("{0}", _currentSetName));

var z = (from x in qry
where x.Active
orderby x.Name
select x);
_currentSet = z;
bs.DataSource = _currentSet;
}

NOTES:

  • _currentSet is of type object and is used to hold the data returned by our object query which in turn we use as the DataSource of our bs (BindingSource)
  • We only load Active entities(records)
  • entityType parameter comes as a result of user selecting the definition data through a lookup control. We idenitfied the real type of definition entities in Step-3 and filled the lookup control.

Here is how the final editor looks like

This is a Turkish application so Tanımlar is the lookup where user selects the definition entity, the description displayed in the lookup directly comes from the Description attribute we have talked about in Step-2

Handling Concurrency Exceptions

EF4 supports optimistic concurrency scenarios through Concurrency Mode property residing on the entities. You just simply set Concurrency Mode = Fixed on any property you want to be included in the concurrency check process and EF handles the rest for you. Behind the scenes EF includes the old values, that is values when the entity was materialized for the first time in the ObjectContext, of the properties incorporating to the concurrency checks in the where clause of update and delete statements. When the statment is executed against the database and returned row count is zero EF infers that record was modified by another user/process which in turn causes concurrency exception to be thrown. Simple and powerfull for most scenarios. But I shall warn you about using timestamp columns for this scenario. Typically in Sql Server timestamp column is used to identify if the record was modified since the last time you fetched the record. But in parent/child constructs in case of a child entity update EF also issues a fake update on the parent entity which causes the timestamp value of the parent to be updated, which in turn causes concurrency exceptions for the parent entity even the entity was not explicitly modified by another user or process. This sort of behaviour is caused by the assumption that when a child entity of a parent entity is modified this also might have caused a conceptual modification to the parent entity. But this assumption does not apply to all, may be most, the time. In this case you have to implement your own strategy for modification marking. A simple solution can be found here. We used the sample there as a starting point to implement our own.

Too much intro to optimistic concurrency, anyway. When you get a concurrency exception you have two choices

1) Inform user about the problem and reload the data automatically

2) Inform user about the problem and give user the option to decide what to do; reload data (StoreWins) or overwrite the data on the database (ClientWins)

We went with option 2 and present a dialog whre our users can select what to do next. This kind of implementation is not very straight forward, especialyy if you are dealing with complex user interface presenting lots of related information for a single entity(record). We faced some problems with the Refresh method of the ObjectContext. You need to know exactly which entity or entityset to refresh which is sometimes not possible, because you just simply bound your user interface to propertes of an entity.

Here is a sample SaveChanges implementation where we try to handle concurrency exceptions

    /// <summary>
/// Asks user for confirmation if there are changes on the object context and persist changes
/// </summary>
/// <param name="confirm">Ask user for confirmation</param>
/// <returns>Returns true if user does not allow changes to be persisted</returns>
private bool SaveChanges(bool confirm)
{
if (!SessionConsts.CanPrincipalEditProjects)
return true;

ucProjectEditor1.EndEdit();
ucComissionMemberList1.EndEdit();

bool isNewProject = ucProjectEditor1.IsNew;
// 1)Object contex has modified, deleted or new objects
// 2)or we try to save a new object
if (_objectContext.HasChanges || isNewProject)
{
if (!confirm || MessageBoxHelper.ShowYesNo("Save changes?") == System.Windows.Forms.DialogResult.Yes)
{

// Validate project properties
bool projectOk = ucProjectEditor1.ValidateUserInput();

//Validate comission member properties
bool membersOk = ucComissionMemberList1.ValidateUserInput();

// We have problems with user input
if (!projectOk || !membersOk)
{
// Build the error message
StringBuilder errors = new StringBuilder();
if (!projectOk)
{
errors.AppendLine("Project definition errors.");
errors.AppendLine(ucProjectEditor1.GetUserInputErrors());
}
if (!membersOk)
{
errors.AppendLine(ucComissionMemberList1.GetUserInputErrors());
}
MessageBoxHelper.ShowError("Can not save project.Please correct the errors.\r\n\r\n" + errors.ToString());
// Cancel save operation
return false;
}

// We have a new project so we have to add that object to context
if (isNewProject)
_objectContext.Projects.AddObject(ucProjectEditor1.Project);

using (WaitDialogForm waitDlg = GeneralUtils.WaitDlg("Saving changes..."))
{
try
{
// Try to save
_objectContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave | SaveOptions.DetectChangesBeforeSave);

// Save is sucessfull so we refresh editor captions
ucProjectEditor1.RefreshCaption();
ucComissionMemberList1.RefreshCaption();

// If that was a new project we refresh the project list
// without reloading the current project in the editors
if (isNewProject)
LoadProjects(false);
}
// We got optimistic concurrency error
catch (OptimisticConcurrencyException oce)
{
// Ask user what shall be done
// Option 1) Load data from database
// Option 2) Keep user data and automatically save
waitDlg.Hide();
RefreshMode mode = OptimisticConcurrencyExceptionDlg.ShowForm(oce);
try
{
// Refresh the project and the comission members collection
_objectContext.Refresh(mode, ucProjectEditor1.Project);
_objectContext.Refresh(mode, ucProjectEditor1.Project.ComissionMembers);

// Project was delete in another session but we try to update in current session
// In this case refresh suceeeds but the object is not in the context anymore
// so we need to reload another project to the editor
if (!IsProjectStillInContext())
{
waitDlg.Hide();
MessageBoxHelper.ShowError("Proje başka bir kullanıcı tarafından silinmiş veya değiştirilmiş.");
LoadProjects(true);
return false;
}
}
// If ClientWins is selected by the user and master or details records can not be found we get an exception
catch (Exception)
{
waitDlg.Hide();
MessageBoxHelper.ShowError("Proje veya bağlı kayıtlar başka bir kullanıcı tarafından değiştirilmiş veya silinmiş.\r\nLütfen proje listesini tazeleyerek tekrar deneyiniz.");
return false;
}

if (mode == RefreshMode.ClientWins)
{
try
{
waitDlg.Show();
_objectContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave | SaveOptions.DetectChangesBeforeSave);
ucProjectEditor1.RefreshCaption();
ucComissionMemberList1.RefreshCaption();
}
// We can not apply client values to the master or detail records.
catch (Exception)
{
waitDlg.Hide();
MessageBoxHelper.ShowError("Can not save changes.\r\nProject record or any other related record was deleted by another session\r\nPlease refresh the Project list and try again.");
LoadProjects(true);
return false;
}

}
}
catch (UpdateException upex)
{
waitDlg.Hide();
if (!GeneralUtils.TryDisplayUniqueIndexError(upex))
throw upex;
else
return false;
}
return true;
}
}
//else
//{
// if (!isNewProject && !isExplicitSave)
// _objectContext.Refresh(RefreshMode.StoreWins, ucProjectEditor1.Project);

// return true;
//}
}


return true;
}

There is lots of code in this method but I just want you to concantrate on these lines

  • Line 56: We call SaveChanges to persist changes to the database
  • Line 68: We catch the optimistic concurrency exception
  • Line 74: We present option dialog where our users can choose what to do next
  • Line 78 and Line 79: We call Refresh with user selected mode for our Project entity and ComissionMembers EntitySet (Luckily we know what to refresh :)
  • Line 100-118: If user selected ClientWins mode we re-issue SaveChanges so that user changes will be persisted to the database and overwrite the values in the database

Here is our dialog where we ask our users what to do next in case of a concurrency exception. Again the dialog is in Turkish, for clarification first option states that StoreWins, that is changes of the user will be discarder, second options states that ClientWins, that is changes made by the user will overwrite the database.

 

UnitOfWork (ObjectContext) Decisions on WinForms

UnitOfWork is a core concept introduced in all ORM frameworks implicitly or explicitly and each ORM wrap/implement this concept through some constructs. EF4 has ObjectContext class and EF generates a named class inherited from ObjectContext for your use. If you want EF to get data or persist data from a database your entry point is your named ObjectContext class. EF materializes your entities inside your ObjectContext instance, and once you detach your entities from your object context you can not persist them to the database anymore.

Creating an instance of ObjectContext is not performance sensitive action, but when you begin populating the object context with entities you must be very carefull. If you keep you object context instance in memory for a long time and perform too much data operations your object graph may get too complicated and you will have thousands of objects in your object context, which in turn will cause you major performance issue on the client side. So be carefull when instantiating object context instances and plan carefully for how long they will be alive and do not forget to dispose them when you are finished.

In web application scenarios most ORM frameworks recommend that boundaries of UnitOfWork shall be defined by the request, that is when request arrives your unit of work starts and when request is completed/processed the unit of work ends. This is pretty effective strategy for web, but for smart client applications we do not have requests. We have to plan carefully and may be apply different strategies based on the application flow. Anyway, still we have some clues for WinForms

  • ObjectContext per form
  • ObjectContext per user control
  • ObjectContext per use case

In our application we used all of the strategies specified above. We have forms with single object context, we have user controls which manage their own object context as well as some user controls just use the object context of the parent form. We also use seperate object context per use case in some wizard style interaction scenarios. Overall be carefull while defining your unit of work, else you will have memory issues and have to handle detached objects manually.

Audit Logging with Object Context

Most of the applications provide some sort of audit/trail logs in different detail levels. Some applications just keep track of who/when created/modified the record as the property of the actual record, some other keep more detailed information in seperate databases or tables. In our application we used both approaches, for some not so critical data we just track who/when created/modified the record, for some sensitive and more complicated data we keep track of changes in seperate tables.

With EF4 audit logging is some sort of simple, you just hook to SaveChanges event of your ObjectContext class and get information about the changed entities from ObjectStateManager of your object context instance. This is trivial, here is an example

public class ContextInterceptor : IDisposable
{
private eXpressOtoEntities context;

public ContextInterceptor(eXpressOtoEntities context)
{
this.context = context;
this.context.SavingChanges += new EventHandler(WhenSavingChanges);
}


public void Dispose()
{
if (this.context != null)
{
this.context.SavingChanges -= new EventHandler(WhenSavingChanges);
this.context = null;
}
}

void WhenSavingChanges(object sender, EventArgs e)
{
// Query ObjectStateManager and get Modified, Added and Deleted entities
foreach (var item in this.context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified | System.Data.EntityState.Added | EntityState.Deleted))
{
object entity = item.Entity;
// Perform audit logging or whatever you want
}
}
}

ContextInterceptor class is just a utility class, you could write the code in your ObjectContext class as well.

 partial class eXpressOtoEntities
{

partial void OnContextCreated()
{
// Automatically attach an ContextInterceptor on each new context:
new ContextInterceptor(this);
}
}

We simply create ContextInterceptor whenever a new ObjectContext instance is created.

So far so good, hooking is trivial inserting log records is simple too; create audit log entities and attach them to the context and save as usual. But there is an important point you should be aware of, which is optimistic concurrency. You get optimistic concurrency exception after your call to SaveChanges and your delegate WhenSavingChanges is executed, you will get the exception after attaching your log entities to the context. If you provide recovery method to the users, as I explained in the "Handling Concurrency Exceptions" section users will be able to issue another SaveChanges on the same context which will cause another set of audit log entities to be created and you will persist duplicate log entries to the database. To avaoid this problem you shall identify and remove detached log entries at the beginning of your WhenSavingChanges delegate. Here is the modified version of WhenSavingChanges method of ContextInterceptor class

 void WhenSavingChanges(object sender, EventArgs e)
{
context.DetachAdded<VehicleModelZeroPriceLog>();
context.DetachAdded<JobOrderStateLog>();

// Query ObjectStateManager and get Modified, Added and Deleted entities
foreach (var item in this.context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified | System.Data.EntityState.Added | EntityState.Deleted))
{
object entity = item.Entity;
// Perform audit logging or whatever you want
}
}

// Excerpt of eXpressOtoEntities demonstrating DetachAdded<T> method implementation
partial class eXpressOtoEntities
{
// .....
// Other stuff here
// .....
public void DetachAdded<T>()
 {    
List<ObjectStateEntry> logEntries =
ObjectStateManager.GetObjectStateEntries(EntityState.Added).Where<ObjectStateEntry>(e => e.Entity.GetType() == typeof(T)).ToList<ObjectStateEntry>();
  logEntries.ForEach(delegate(ObjectStateEntry e)
  {
   this.Detach(e.Entity);
  });
}
}

DetachAdded<T> method simply detaches newly added entities of a specific type, in our case we use this method to detach any newly created entities of type VehicleModelZeroPriceLog and JobOrderStateLog. So with this little utility we will not get duplicate log entries in case of a recovery scenario from concurrency exceptions

Conclusion

Working with EF4 was a smooth experience, having an ORM background it was pretty easy to discover the shortcomings stated in this post. I even had fun working with EF4. I also posted some bugs and improvements regarding the Visual Studio 2010 and Model Designer to Microsoft.

I'm also looking forward to test how EF4 fits in a more layered architecture and if it is possible to implement the Repository Pattern. I will try to post as I experience different aspects of EF4.

Stay tuned...


Posted in: .NET Development , Entity Framework  Tags:

We have just finished development of our new product MoodleTouch (mTouch) and will submit mTouch to the AppStore for review next week after we complete our tests. mTouch is the first and only native IPhone application for Moodle and we are already proud of this achievement. We have made extensive use of our JiraTouch experience both on technical side as well as on customer expectations side. mTouch desktop version was born out of our customer expectations experience gained from JiraTouch. Let me explain the details.

Moodle is an open source system, and has lots of customized installations spread all around the world. Moodle does not offer an API for 3rd party clients so you can not simply access a strictly controlled and neat API which you can develop against. To overcome this limitation we use some visual pattern matching techniques to make Moodle output fit on the IPhone, you can think mTouch as a customized somehow intelligent browser for Moodle which is optimized for IPhone screen size and utilizes IPhone UI best practices. As I said visual aspects of each Moodle installation may vary so that these changes may cause mTouch not to play well with some Moodle installations which in turn will bring unhappy students. Students will be unhappy because they will have hard times if they want to get refund from the AppStore, probably this will not even be possible. Students will also be unhappy because they will not be able to access Moodle on a trip and post to a forum which will be closed in just a few minutes. From our side mTouch will be interpreted as an application which works on some Moodle sites but not on others which means bad fame.

So we decided to provide a free Windows version of mTouch so that students can download and play to see if mTouch works properly with their Moodle installation and experience the mTouch capabilities and afterwards decide to buy or not. We did not choose to publish a light/free limited version of mTouch because we want the students to experience all of the mTouch functions before they buy the application.

Check out MoodleTouch site for details

Download mTouch for Windows version

Contact us for more information


Posted in: IPhone , MoodleTouch , MTouch  Tags:
aliozgur posted on February 22, 2010 10:01

We have been busy developing our new baby JiraTouch for the last 3 months. It has been a tough journey with lots of unknowns and new things. Platform was new, development tools were new and the team was new. The only knowns were Jira and the C# language. I would like to share some of my observations in this blog post.

What is JiraTouch?

You can read JiraTouch features to learn more about JiraTouch.

You can watch video tutorials to see JiraTouch in action.

You can buy JiraTouch from AppStore.

Jira and SOAP API

No need to talk about the quality of Jira software on its own. But I'm sorry that Jira SOAP API is not as complete as the product itself. The most serious problem is the versioning dilemma of the SOAP API. SOAP API is introduced since Jira version 3.0 but over the time (Recent version is Jira 4.01) there have been lots of changes with the API. Change is normal and we do not expect all aspects shall be covered at once, since the product itself matures and changes so does the SOAP API. But I would be more happy if Jira guys developed a good API versioning strategy with good API change documentation. For example with no specific versioning information included in the wsdl you get different properties for the same Type. One perfect example is RemoteComment type, this type has changed dramatically through Jira versions. Here are examples of the WSDL for different jira versions

This snippet is from the wsdl of a Jira 3.6 installation

<complexType name="RemoteComment">
  <sequence>
   <element name="body" nillable="true" type="xsd:string"/>
   <element name="id" nillable="true" type="xsd:string"/>
   <element name="level" nillable="true" type="xsd:string"/>
   <element name="timePerformed" nillable="true" type="xsd:dateTime"/>
   <element name="username" nillable="true" type="xsd:string"/>
  </sequence>
</complexType>

This is wsdl snippet for RemoteComment from Jira 4.01

<complexType name="RemoteComment">
<sequence>
<element name="author" nillable="true" type="xsd:string"/>
<element name="body" nillable="true" type="xsd:string"/>
<element name="created" nillable="true" type="xsd:dateTime"/>
<element name="groupLevel" nillable="true" type="xsd:string"/>
<element name="id" nillable="true" type="xsd:string"/>
<element name="roleLevel" nillable="true" type="xsd:string"/>
<element name="updateAuthor" nillable="true" type="xsd:string"/>
<element name="updated" nillable="true" type="xsd:dateTime"/>
</sequence>
</complexType>

Another very major difficulty I think is how Jira handles/expects date and time values. When you get some entity having datetime data from Jira with the SOAP API, you get UTC formatted datetime value and that is ok. But since some specific Jira versions does not provide information about the Jira server's datetime we are not able to perform timezone specific conversions which in turn causes our clients to view wrong or more specifically locale datetime values and as well submit locale datetimes to the Jira server. To handle this deficiency we had to include in JiraTouch a time zone selection if we could not get server datetime automatically from Jira server, which is an extra configuration overhead for our clients. Jira's date and time handling is long debate in Jira community and among Jira customers as well, current Jira versions can not handle different time zones as far as we investigated Jira customers have requirements about this concern and we hope Jira guys will develop a smart way to handle different timezonse at some point.

Custom fields were another headache. Jira has very handy and highlghy configurable custom field support. You can define most of the custom fields you need, but SOAP API has limited support for the custom fields. One major problem is you get dictionary of custom fields for a RemoteIssue type but you just have custom field id and the value, there is no label/name included.

Here is the wsdl definition for a remote custom field

<complexType name="RemoteCustomFieldValue">
 <sequence>
   <element name="customfieldId" nillable="true" type="xsd:string"/>
   <element name="key" nillable="true" type="xsd:string"/>
   <element name="values" nillable="true" type="impl:ArrayOf_xsd_string"/>
 </sequence>
</complexType>

Since you get no label what shall we display to the user the id and the current value? Not so user friendly. The only way to get label/name of the custom fields is through getCustomFields soap method, but there is one little problem you have to be logged in as an administrative user in order to call that method! That is not so cool but with some tweaking we could overcome this limitation without requiring adminsistrative login.

The last thing I want to point about Jira SOAP API limitations is that mighty "time tracking" field dilemma, more generally some explicitly required but not included on RemoteIssue type properties. These properties are somehow predefined custom system fields but createIssue method of SOAP API does not support these kind of fields properly. Again to overcome this issue some little fancy tricks need to be done.

These were some of the problems we faced with the well known part of the project.

Mono, MonoDevelop and MonoTouch

I believe that Mono and MonoTouch are very valuable efforts. I will not waste your time telling you why they are valuable you can find lots of arguments around, but as a Microsoft platform developer and a .NET developer I'm pleased with the existence of Mono and MonoTouch.

The major headache we had during JiraTouch development regarding Mono was MonoDevelop. Compared to Visual Studio MonoDevelop feels like a not so cool notepad. The worst thing about MonoDevelop is unstability, it might crash, freeze or code editor just decide not to paint some of the brackets you type. For example if you reference assemblies with auto incremented version numbers (that is 1.0.*) MonoDevelop can not refresh your references successfully and as a result you get "missing type" compile time errors. MonoDevelop debugger also has some problems, you may need to click multiple times so that debugger can be attach to IPhone simulator, MonoDevelop may crash while you try to evaluate a variable during debugging, you may get "Can not evaluate" error while trying to see variable values and you can not just copy/paste the contents of the evaluation window.

We designed JiraTouch so that we could develop Model and UI assemblies seperately, so for a long time we tried to develop Model assembly on OpenSUSE with MonoDevelop to ensure maximum level of framework compatibility when we reference that assembly from the UI (IPhone application actually) which was being developed on Mac OSX. After spending some time struggling with MonoDevelop we decided to switch to Visual Studio and do rest of the Model assembly development with Visual Studio which in turn caused some framework incompatibilities I will demonstrate you just in a second.

Another major problem was missing System.Web.Services.dll in MonoTouch. During development we used to generate Jira service proxy on openSUSE, include the generated code in the project and reference an unofficial version of System.Web.Services.dll. That approach worked well for a while until we decided to compile our IPhone application with "Link SDK assemblies only" option which caused our approach to fail. So we had to give up with that linker option and try to survive with a larger application size, until Mono decided to include an official System.Web.Services.dll for MonoTouch which just worked well with the linker option.

We faced framework level implementation differences as a result of choosing Visual Studio as the main tool for Model development. The biggest issue we faced was with XmlReader and XmlTextWriter implementations. In Microsoft's implementation WriteNode works perfectly with element attributes while Mono implementation just writes the first attribute and ommits the rest. So we had to traverse all elements and perform WriteAttributes, WriteRaw, WriteStartElement and WriteFullEndElement based on the element types. This difference was hard to discover and hard to resolve which we had to spend much more time than we expected.

Yet another frameowork level implementation difference was with HttpWebRequest.PreAuthenticate we faced while developing the Social integration parts of JiraTouch. On Microsoft and Mono when you specify PreAuthenticate to be true and add an Authorization header to the request both frameworks continue to send that header to the server after the first request, but on MonoTouch Authorizaton header is not sent to the server after the first request which is absolutely a normal behaviour. Again this difference caused us couple of frustrating debug sessions, but we are happy that we discovered that issue before launching JiraTouch.

The last difficulty we faced I want to mention is that magic "Link SDK assemblies only" option. If you build you IPhone application with this switch MonoTouch performs some optimizations during compile time thus producing a smaller application in size. Smaller size means a lot in iTunes and AppStore world, because if your application(actually ipa file, which is compressed package of your application) is larger than 10MB you will not be listed for OTA downloads which in turn means that you will not reach some portion of IPhone users. So we decided to use this option, but we ignored some facts about using this options and Mono documentation does not specify exactly what considerations apply if we use this options. It is simply stated that some of the reflection and serialization related functionality can cause runtime errors. Yes that is true we had runtime errors but we would be pleased if the compiler could warn us about these issues. One simple example was the runtime error we got from a code snippet which was simply performing Linq query on an array of enumerations. The code was something like this

var enums = Enum.GetValues(typeof(SomeEnumerarion));

var selectedValue = from e in enums where e.ToString() == "EnumValue1" select e;

The sample code snippet worked well while debugging with "Link SDK assemblies only" option but when we tested JiraTouch on an IPhone we used to get runtime errors regarding MonoTouch and AOT (ahead of time compiling, since on IPhone JIT compilation can not be performed MonoTouch uses AOT compiling to support generics, linq and other stuff). We just changed the code and dropped the Linq query and the problem was solved. As I said we would be happier if MonoTouch compiler warned us with that possible runtime problem.

Review Process; iTunes and AppStore

We had no problems during the process of submitting JiraTouch for review over iTunes. We submitted on the weekend and JiraTouch status changed to "In Review" on Tuesday and we got approved on Friday. We got the approval within 3 days that was amazing.

What is our vision?

We argue that JiraTouch is the most complete Jira client specifically optimized for IPhone. We tried to cover most of the Jira functionality so that a Jira user can perform almost everything with JiraTouch. We believe that we succeeded to get to that completeness level as far as Jira SOAP API allowed us and a little bit beyond what Jira SOAP Api offers. Our vision was to provide the highest possible level of Jira functionality with some unique features like Social integration, which allows JiraTouch users to update their twitter,facebook, linkedin and yammer accounts.

In the future we intend to provide more unique features to JiraTouch users, which will be focused mainly on sharing and social communities. We already started evaluating these unique ideas and hope to include these fatures with the next version of JiraTouch.

What is PragmaTouch?

We decided to gather all touch enabled device software development under the PragmaTouch brand. PragmaTouch will be the brand supporting primarly JiraTouch. We will provide consulting and developing custom touch enabled device projects under PragmaTouch brand as a group of independent software developers.

Epilogue

I would like to thank to my colleagues Tolga and Ahmet. They did a fantastic job and helped me much while managing this project.

 


Posted in: IPhone , MonoTouch  Tags:

Downloads

Original project is here

Modified binaries: IIS_LogAnalyzer_Bin.rar (360.01 kb)

Patch file : Indihiang_LogAnalyzer_FTPSupport.patch (170.94 kb)

Screen Shots

 

 


 

Note for Vista Users

Modified version creates a TempDir under the application installation folder and downloads files there. Vista does not allow regular user to create directories under Program files so if you install the application under Program Files , right click on the Indihiang.exe, click Properties and check "Run this program as an administrator" option found in Compatibility page.

 


aliozgur posted on October 7, 2009 10:47

Yesterday I visited Rob Conery's blog and the post about commercial SubSonic support options made me think again about the open source philosophy. In my opinion Rob must decide in which category of Open Source is SubSonic located.

  • Is it a real open source project as defined by OSI
  • Is it an open source project in a way ASP.NET MVC is

If SubSonic is in the first category, I believe NHibernate is in that category, Ayende’s commerical support offering is not acceptable. Since bug fixes are included in that offering and Rob or Ayende are commiters that would not sound right to the community.

If SubSonic is in second category and Rob decide that SubSonic is open source but main official release is maintained and owned only by him or a company that commericial support offering would be ok.

Perfect Examples

Following OSS examples are very well suited to define my objection

Linus Torvalds does not offer bug fixes as a commerical support for the official Linux kernel. He does not because he is the main authority, and the unpaid authority, who decides if a bug fix or patch be applied to the official release of the kernel. (I do no think he has the time to review all submitted patches but he in a way organized the inner workings) But we all know that Suse and RedHat offer bug fixes and patches for their own distribution, which is understandable and valid. I do not mind the way RedHat or Suse patches and bug fixes are applied to the official kernel releases.

Another example is the Mozialla Foundation. If NHibernate had a non profit foundation as Mozilla and the foundation offered commercial support via kind of Mozilla Corporation that would be OK too. And I want to remind you that Mozilla like foundations do not distribute share profit to any third parties.

Questions

  1. As far as I know NHibernate is not copyrighted to anybody or any entity. So may other contributors claim copyright for the bugs they introduce which may cause some complications?
  2. The material itself and the functionality that material provides is not paid in OSS projects. Does offering commercial bug fix support right for the official release of the project cause the material to have some sort of monetary value, since fixing bugs is commercialized which means introducing bugs may be commercialized too?
  3. What if I, as a non commiter to NHibernate project, wanted to offer commercial bug fix support too? Do you think that project leads would allow me to be a committer just beacuse of that even if I'm not qualified to be a commiter? Shall I interpret Ayende as monopoly in NHibernate community context? Don't you think that being a virtual/possible monopoly conflicts with the open source?
  4. If an OSS is not copyrighted to anybody or any entity, do you think that OSS project leads hold legal rights to decide whom to let in or kick out?


Posted in: General Development  Tags:
aliozgur posted on August 14, 2009 12:32

For a while I'm trying to align a technology toolset for Web 2.0 development. Recently I decided to go with Microsoft .NET technologies and JQuery.

Here are the tools I'm provisioning to utilize

  • ASP.NET MVC and JQuery
  • ADO.NET Entity Framework
  • WCF
  • May be ADO.NET Data Services and ADO.NET Dynamic Data

There is already a jQuery LighBox Module for Cuyahoga 1.6 but in my case I have a Cuyahoga 1.5.0 installed with some custom modules and can not use that module. Here are the steps you have to perform to use jQuery LighBox Plugin with a Cuyahoga 1.5.x installation.

  1. Dowload jQuery LighBox plugin from here.
  2. In your Cuyahoga installation root browse to js folder and create JQueryLightBox folder under that js folder
  3. Open jquery.lightbox-0.5.min.js file found in the downloaded package and replace
    • 'images/lightbox-ico-loading.gif' with '/images/lightbox-ico-loading.gif'
    • 'images/lightbox-btn-prev.gif' with '/images/lightbox-btn-prev.gif'
    • 'images/lightbox-btn-next.gif' with '/images/lightbox-btn-next.gif' 
    • 'images/lightbox-btn-close.gif'with '/images/lightbox-btn-close.gif'
    • 'images/lightbox-blank.gif' with '/images/lightbox-blank.gif'
    and save your changes
  4. Copy jquery.js and jquery.lightbox-0.5.min.js files found in the downloaded package to JQueryLightBox folder created in the previous step
  5. Create a folder named css under your Cuyahoga installation root and create JQueryLightBox folder under that css folder
  6. Copy jquery.lightbox-0.5.css found under css folder inside the downloaded jQuery LighBox package to JQueryLightBox folder created in the previous step
  7. In your Cuyahoga installation root browse to Images folder and copy the image files found in under images folder of the downloaded jQuery LighBox package to the Cuyahoga Images folder.
  8. In your Cuyahoga installation browse to Templates folder and find the ascx file under the current template folder you are using
  9. In the head section of your ascx file add these lines

  10.   <script type="text/javascript" src="../../js/JQueryLightBox/jquery.js"></script>
      <script type="text/javascript" src="../../js/JQueryLightBox/jquery.lightbox-0.5.min.js"></script>
  11.  At the end of the ascx file just before the closing of body tag add the following js code
  12. <script type="text/javascript">
    $(function() {
        $('a.lightbox').lightBox(); // Select all links with lightbox class
    });
    </script>

  13. Add links to your images to enable jQuery LightBox for your images. Here is the template link 
  14.  <a title="Title here" class="lightbox" href="Link to your original image file"><img border="0" alt="" src="Link to the thumbnail image file if you wish to use thumbnails, if not you can remove this img tag" /></a>
     
  15. See jQuery LightBox in action


Posted in: Cuyahoga  Tags:
aliozgur posted on June 2, 2009 16:59

After being named as Best General Database Tool by CodeProject readers PragmaSQL decided to publish a free Personal Edition.

You can download PragmaSQL Personal from here


Posted in: PragmaSQL News  Tags:
PragmaSQL was named as Best General Database Tool by The Code Project’s members.
Members were asked to rate their favorites on CodeProject. The Code Project staff then compiled the highest rated listings, awarding the highest ranked in each product category. The results reflect actual perceptions of what developers value. Each codeproject.com member decides which companies or products deserve recognition, based on in-the-field experience.  

Posted in: CodeProject  Tags: