Introduction

PragmaTouch team is currently working on a new e-learning project. Below you can see a conceptual system diagram.

Users who access the Management UI inside the ASP.NET MVC 3 application are the content producers and they will access the system from standard web browsers to produce the content. Users who will consume the content (depicted at the bottom of the diagram) will access the system through our official mobile applications and other 3rd party applications. Our official applications and other client apps read/write data to the system through our Web API JSON.

We evaluated some options like OAuth, OAuth2 and simple API key authentication during the development process. All of the standard methods we have evaluated were too standard to implement or not secure enough. So we decided to go for our own simple but yet fairly secure API authentication mechanism.

API Authentication Ticket Request

On the server side authentication ticket requests are handled by an authentication controller which simply checks if "Request Validation Parameters" sent by the client are valid. If validation parameters are valid authentication controller generates a ticket and sends the ticket as JSON data to the client. Here is the authentication controller code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using Newtonsoft.Json;
using System.Globalization;

namespace PragmaTouch.WebApp
{
    public class AuthTicketController : Controller
    {
	    private readonly IAuthRequestValidator _authRequestValidator = null;
		public AuthController(IAuthRequestValidator authRequestValidator )
		{
			_authRequestValidator = authRequestValidator;
		}
		
        public ActionResult Index(string p1, string p2)
        {
          if (!_authRequestValidator.IsAuthRequestValid(p1,p2))
          {
            var authData = new AuthData { Ticket = String.Empty , Success = false, Error = "Invalid validation parameters"};
            return Json(authData, JsonRequestBehavior.AllowGet);
          }
          var ticket = new AuthTicket 
          { 
            ApiKey = "apikey_comes_here",
            P1 = p1,
            P2 = p2 
          };
          ticket.SetDefaultExpiresOn();

          JsonNetResult result = new JsonNetResult();
          result.Formatting = Formatting.Indented;
          result.Data = ticket.CreateEncryptedAuthData();
          return result;
        }

        public ActionResult ServerDateTime()
        {
          JsonNetResult result = new JsonNetResult();
          result.Formatting = Formatting.Indented;
          result.Data = new { dateTime = DateTime.Now };
          return result;
        }
    }
}

 

  • IAuthRequestValidator instance is injected by Ninject.MVC
  • Upon successfull validation AuthTicket is generated including the validation parameters and an empty ApiKey value. ApiKey value is a shared secret both by the server and client. Server does not put the Api Key value into the AuthTicket intentionally because the server will expect the client to populate the key to AuthTicket on subsequent API calls
  • Server sets a default expiration for the ticket.  
  • AuthTicket is encrypted by the server and the result is served to the client as AuthData JSON object.

API Request

 

The client application adds the authentication ticket (serialized as JSON) into the Authorization header of every API request. On the server side we implemented an ApiAuthorizeFilter attribute which intercepts the requests to the secured API actions and validates the authentication ticket included in the Authorization header of the request. Here is the code for the ApiAuthorizeFilter attribute

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;

namespace PragmaTouch.WebApp
{
  public class ApiAuthorizeAttribute:AuthorizeAttribute
  {
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
      var authorizationHeader = httpContext.Request.Headers["Authorization"];
      if (String.IsNullOrWhiteSpace(authorizationHeader))
        return false;

      try
      {
        AuthData authData = JsonConvert.DeserializeObject(authorizationHeader);
        AuthTicket authTicket = JsonConvert.DeserializeObject(authData.Ticket.Decrypt());
        DateTime expiresOn = DateTime.Now.AddDays(1);
        
        if (ConfigHelper.CheckForExpiredAuthTicket)
          expiresOn = AuthTicket.ParseExpiresOn(authTicket.ExpiresOn);
        
        return authTicket.ApiKey == ConfigHelper.ApiKey && expiresOn > DateTime.Now;
      }
      catch
      {
        return false;
      }
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
      var result = new JsonNetResult();
      result.Formatting = Newtonsoft.Json.Formatting.Indented;
      result.Data = new AuthData{Success = false, Error = "Authorization required"};
      filterContext.Result = result; 
    }
  }
}

 

  • ApAuthorizeAttribute simply checks if the authentication ticket has a valid Api Key value and if authentication ticket has expired (to minimaze chance of reply attacks)
  • Expiration control is optional and can be turned on/off with a value specified in the web.config file of the ASP.NET MVC 3 application
  • The same crypto algorithm and crypto keys are used on both sides (the server and client)

 

Refreshing the Authentication Ticket

Clients can refresh the authentication ticket using two alternatives

  1. Simply request for a new authentication ticket
  2. Call the ServerDateTime action in the AuthTicketController to find out the current server datetime then add some extra time to the ExpiresOn value of the authentication ticket if ticket has expired.

Sample Client Code

public class SampleApiClient
{	
	public class ServerDateTime
    {
      public string dateTime { get; set; }
    }

    private AuthData _authTicket = null;
	private bool ApiAuthenticate(stirng p1, string p2)
	{
		_authTicket = null;
		try
		{
		string apiUrl = "http://localhost/AuthTicket";
		WebClient wc = new WebClient();

		string authDataJson = wc.DownloadString(String.Format("{0}?p1={1}&p2={2}", apiUrl, p1, p2));

		_authTicket = JsonConvert.DeserializeObject(authDataJson);
		if (!_authTicket.Success)
		{
		  return false;
		}

		var authTicket = JsonConvert.DeserializeObject(_authTicket.Ticket.Decrypt());
		authTicket.ApiKey = ConfigHelper.ApiKey;
		_authTicket.Ticket = JsonConvert.SerializeObject(authTicket).Encrypt();
		return true;
		}
		catch (Exception ex)
		{
			// Do some error reporting
			throw ex;
		}
	}
	
	public bool GetServerDateTime(out DateTime dateTime)
    {
      dateTime = DateTime.MinValue;
      string apiUrl = "http://localhost/Api/AuthTicket/ServerDateTime";
      if (String.IsNullOrWhiteSpace(apiUrl))
        return false;
 
      WebClient wc = new WebClient();
      string jsonResult = wc.DownloadString(apiUrl);
      ServerDateTime result = JsonConvert.DeserializeObject(jsonResult);
      dateTime = AuthTicket.ParseExpiresOn(result.dateTime);
      return true;
    }
	
	public void ApiExpireAuthTicket()
    {
      if (_authTicket == null || String.IsNullOrWhiteSpace(_authTicket.Ticket))
        return;

      var authTicket = JsonConvert.DeserializeObject(_authTicket.Ticket.Decrypt());
      authTicket.ExpiresOn = String.Empty;
      _authTicket.Ticket = JsonConvert.SerializeObject(authTicket).Encrypt();
    }
	
    public bool RefreshAuthenticationTicket(object sender, EventArgs e)
    {
      if (_authTicket == null || String.IsNullOrWhiteSpace(_authTicket.Ticket))
        return;

      DateTime serverDateTime = DateTime.Now;
      if (!GetServerDateTime(out serverDateTime))
      {
        return false;
      }
      
      var authTicket = JsonConvert.DeserializeObject(_authTicket.Ticket.Decrypt());
      authTicket.ExpiresOn = AuthTicket.CreateExpiresOnString(serverDateTime.AddHours(12));
      _authTicket.Ticket = JsonConvert.SerializeObject(authTicket).Encrypt();
	  return true;
    }
	private string ApiRequest(string apiRequestUrl)
    {
      try
      {  
        MyWebClient wc = new MyWebClient(_authTicket);
        return wc.DownloadString(apiRequestUrl);
        
      }
      catch (Exception ex)
      {
			// Do some error reporting
			throw ex;
      }
    }
	
	
}

Here is the custom WebClient class which is used to add the authentication ticket to the request Authorization header as JSON serialized data.

public class MyWebClient:WebClient
{
	AuthData _ticket = null;
	public MyWebClient():base()
	{

	}

	public MyWebClient(AuthData ticket):this()
	{
	  _ticket = ticket;
	}

	protected override WebRequest GetWebRequest(Uri address)
	{
	  WebRequest request = base.GetWebRequest(address);
	  if (_ticket != null)
		request.Headers.Add("Authorization", JsonConvert.SerializeObject(_ticket));

	  return request;
	}
}

 


I love MonoTouch, but sometimes MonoTouch lets me down very very bad. The latest scenario was simple in theory. The scenario is

  • Create an HttpWebRequest
  • Provide the NTLM credentials of the user to the HttpWebRequest

The helper method below simply creates and returns an HttpWebRequest

 private HttpWebRequest CreateRequest_NTLM(string url, string username, string password, string domain)
 {
    HttpWebRequest result = (HttpWebRequest)WebRequest.Create(url);
    NetworkCredential networkCredential = new NetworkCredential(username, password, domain);
    CredentialCache credentialCache = new CredentialCache();
    credentialCache.Add(new Uri(url), "NTLM", networkCredential);
    result.Credentials = credentialCache;
      

    System.Net.IWebProxy proxy = System.Net.WebRequest.DefaultWebProxy;

    if (proxy != null)
     result.Proxy = proxy;
      
      
    result.Timeout = 30000;
    result.Method = "GET";
    return result;
 }

Here we create the HttpWebRequest and call BeginGetResponse

 private AuthenticateUser(string username, string password, string domain)
 {
	HttpWebRequest request = CreateRequest_NTLM("http://www.protectedweb.com/",username,password,domain);
	request.BeginGetResponse(new AsyncCallback(AuthenticateUserCompleted),request);
 }
 private void AuthenticateUserCompleted(IAsyncResult asyncResult)
 {
	//Upon successfull authentication some business code executes here 
 } 

Below is the WireShark capture output when the code is run on .NET Framework on a windows machine

Below is the WireShark capture output when the code is run iOS simulator on Mac OSX

As you can see HttpWebRequest of MonoTouch just hangs after the first 303 response of the server and our AuthenticateUserCompleted method is never called.


Posted in: MonoTouch  Tags:
aliozgur posted on February 2, 2012 17:07

Recently we have reorginzed our Jira and implemented a User Request project to get the user requests in a single Jira project with all components in place. With this implementation user requests are assigned to our team managers then they decide how these requests will be mapped to internal projects. We also implemented a custom workflow and at some point (User Test) the user request is assigned to the reporter (our users). When our users complete the tesing and indicate success or failure the request is assigned back to the team managers. This implementation is working pretty well. Our users no longer create issues in our internal projects and the team managers can control the workload and schedule of their teams. With this implementation we can also give to the point reports to the management. In future we plan to be able to dedicate a virtual budget for each department our users work for so that we can calculate a virtual cost and time spent reports for each department.

This implementation has one downside so far; when a user request is created team managers, most of the time, create one or more issues in internal projects. Team managers copy the user entered summary and description while creating issues in our internal projects which are then linked to user requests. When we started this project we were just cloning the user requests and then we were moving the cloned user request to our internal projects. But this usage was braking the continuity of the user request issue numbers. For example; when the original user request with key value of UR-1 is cloned  the cloned user request will have the key value of UR-2. When we move UR-2 to our internal project Jira will not reclaim UR-2 for the next user request instead the next user request will have UR-3 as the key value.

We felt uncomfortable with the discontinued issue numbers so we decided not to use clone/move method and just decided to manually copy user entered summary and description to the issues created in our internal projects. Manual copy/paste is tedious and prone to errors so I cecked out the web to see if Jira has some built in plugin which will allow us to Clone/Copy an issue from one project to another project. Unfortunately I found out that Jira does not have this feature or any plugin to perform this task easily.

The next step was to discover if we could implement this plugin ourselves. The book titled "Jira Development Cookbook" by Jobin Kuruvilla from Packt helped me to grasp the details of Jira plugin development. We will develop our own Issue Copy plugin for Jira, when we have some spare time from daily tasks.

I will share the source code of the plugin from my blog once it is completed, so stay tuned and take a look at "Jira Development Cookbook" by Jobin Kuruvilla from Packt if you are interested in Jira development.


Posted in: General Development  Tags:

Oh well... It seems that we are making the same old mistake again. It is hard to articulate my feelings about the trending tablet business. It feels like we are traversing the same path again. To be more clear I guess we again do what we did in the past when the PC business was in its early days. 

History

I'm relatively young and unexperienced character in this software business but as far as I remember from my readings about the evolution of the PC age once hardware vendors used to create their proprietary OSes running only on their hardware and some software companies were making contracts with rest of the hardware vendors for deploying OSes on their platforms. As time went by PC market changed characteristics and more consumers began to purchase PCs. Increase in demand forced hardware vendors to standardize the hardware specs so that they can build cost effective PCs. Then proprietary OSes were replaced by generic OSes like Windows and Linux distros. And today as a consumer when you buy a PC, laptop or netbook you know that you can install Windows or other Linux distributions on your hardware; you believe that it is your right and freedom to use any OS on your hardware.  You should have already noted this scenario is in action right now for the tablet business.

Future

I hope within 5 to 10 years period tablet hardware vendors like Samsung, HTC, Nokia, Sony and otheers will realize the similarity I've tried to articulate above and decide to produce standardized tablet hardware so that we can install either Android or Windows 8 or even better have dual boot option on our tablets. 

Exceptions

  • Apple will not follow this trend as it was the case with PCs
  • Motorola (well actually Google) will probably not follow the trend as well

Early Adopters

As of today Microsoft seems to be on right path since Microsoft has no Windows Phone or Windows Tablet hardware unit. But if rumors about the Nokia acquisition comes true Microsoft will jump in the Exceptions wagon with Apple and Motorola

Lets wait and see...


Posted in: Mobile  Tags:

Son günlerin gündemde tutunamayan konusu Fatih Projesi ciddi vaadleri olan ve ülkemizin geleceğini yakından ilgilendiren bir proje. Bu proje kapsamında yapılması planlanan çalışmalar şu 5 ana başlık altında toplanmış

  1. Donanım ve Yazılım Altyapısının İyileştirilmesi 
  2. e-İçeriğin Sağlanması ve Yönetilmesi
  3. Öğretim programlarında Etkin BT Kullanımı
  4. Derslerde BT Kullanımı İçin Öğretmenlere Hizmetiçi Eğitim
  5. Ağ Altyapısı ve Geniş Bant İnternet Kullanımı ile Bilinçli ve Güvenli BT Kullanımının Sağlanması
Bu maddelerin hepsi Türkiye'de verilen eğitimin kalitesini farklı açılardan arttıracaktır ancak benim değinmek istediğim konular özellikle 1. madde kapsamında yapılması planlanan çalışmaları kapsamaktadır.Donanım ve Yazılım Altyapısının İyileştirilmesi başlığını ayrıntılı bir şekilde incelediğimizde dersliklerin dizüstü bilgisayarlarla donatılmasının amaçlandığını görüyoruz. Basında çıkan haberlerden takip ettiğimiz kadarıyla Milli Eğitim bakanlığı ve hükümet dizüstü bilgisayarlardan çok tablet bilgisayarlara odaklanmış durumda. Bu çerçevede dersliklerin (aslında öğrencilerin) tablet bilgisayarlar ile donatılması çalışmasında hükümet'in özellikle Apple ve Google ile temaslarda bulunduğunu ayrıca yerli bilgisayar üreticileri nezdinde de temasların ve çalışmaların yapıldığını biliyoruz. Bu çalışmaların ve temasların hepsi bu tür bir girişim öncesi karar verme aşamasında önemli ve değerli faaliyetler. Ancak benim kişisel fikrim eğitim'e yönelik tablet bilgisayar donanımının ve bu donanım üzerinde çalışacak işletim sisteminin tasarım ve geliştirmesinin TÜBİTAK çatısı altında kurulacak ekipler ve kamuya ait bir üretici firma tarafından geliştirilmesinin zorunlu olduğu yönünde. Bu çalışmanın tamamen yerli kaynaklar kullanılarak yapılabileceğine inanmama neden olan bazı gerçekleri aşağıdaki gibi özetleyebilirim

Hemen hemen tüm tablet üreticileri kullandıkları donanım parçalarını Çin'de anlaşmalı şirketlere ürettirmektedir. Ancak bu üreticiler kullanacakları donanım'ın tasarımını kendileri yapmakta veya tasarım şirketlerine yaptırmaktadırlar. Bana göre bizim ülkemizde bu donanım bileşenlerini tasarlayabilecek insan kaynağı mevcuttur. Hükümet bu projenin bir başarı hikayesi olmasını istiyorsa derhal bu donanımın tasarımını yapabilecek kişileri tespit etmeli ve gerekirse yurt dışında Apple, Google, Motorola, HTC, Samsung, Sony gibi ciddi üreticilerde çalışmakta olan mühendisleri TÜBİTAK bünyesinde bu çalışmaya katılmaları için ikna etme çalışmalarına başlamalıdır.

Türkiye TÜBİTAK çatısı altında bence çok başarılı bir işletim sistemi olan Pardus'u geliştirmeyi başarmıştır. Çok önemli bir başarı hikayesi olan ve başarılarını sürdüren Pardus yapılanmasına benzer bir yapılanma kendi tablet işletim sistemimiz için de hızla devreye alınmalıdır. Hatta kendi tablet işletim sistemimizi Pardus'un kapsamını genişleterek geliştirmeliyiz. Günümüzün en başarılı mobil işletim sistemlerinden biri olan Android'in çekirdeği ile Pardus'un çekirdeğinin Linux olduğunu göz önüne alırsak bunu başarmak için Amerika'yı yeniden keşfetmemize gerek kalmayacaktır. Diğer yandan bu çalışmada açık kaynak kodlu olan Android kodunu inceleyip gerekli düzenlemeler ve yenilemeleri de rahatlıkla yapabiliriz. Örneğin Android'in Java temelli ve Dalvik kullanan yapısına benzer C# temelli ve Mono bileşenlerini kullanan bir işletim sistemi geliştirebiliriz.

Tasarımı TÜBİTAK tarafından yapılan donanım'ın montajının yapılması, donanım bileşenlerinin üretimin Çin'de yaptırılması, servis desteğinin organizasyonunun sağlanması gibi konularda faaliyet gösterecek %100 devlete ait bir kamu şirketi kurulmalı. Türkiye gibi bilmem kaç haneli büyüme rakamlarını yakalamış ve bilmem kaç miliyar dolar ihracat hedefi olan bir ülkenin bu tür bir kamu şirketi'nin finansmanını sürdürülebilir bir yapıda sağlayabileceği açıktır. (Bu şirket'in özelleştirilmesinin önüne yasal engellerin daha kurulma aşamasında konulması da bence kesinlikle gereklidir)

Uygulama mağzası ve milli eğitim bakanlığının dijital eğitim materyallerine erişime imkan sağlayan içerik mağzası gibi hizmetler sadece yerli yazılım firmalarına ihale edilebilir. Bu şekilde tablet işletim sistemlerinin kalbi sayılan uygulamaların ve içeriğin yönetimi merkezi bir yapı ile daha kolay sağlanabilir.

Geliştirilen tablet donanımı ve işletim sistemi ticari uygulama ve içeriğe kapalı olmalı sadece eğitim amaçlı ücretsiz içeriğe odaklanmalıdır. Böylece donanım ve işletim sistemi üzerinde ticari bir baskı unsuru oluşması veya oluşturulması engellenebilir.

Milli Eğitim bakanlığı Fatih Projesi kapsamındaki tüm okullara hizmet verebilecek bir data center kurarak okullara LMS gibi hizmetleri ortak bir kaynaktan merkezi olarak sunabilir.

TÜBİTAK çatısı altında üniversitelerin de iş birliği ile Türkiye kendi LMS'ini (Learning Management System) geliştirip işletebilir

Teknolojiyi tüketirken çok yakından takip eden fakat özellikle devlet'in vatandaşlarına sunmakla yükümlü olduğu hizmetlerin sağlanmasında teknoloji yokmuş gibi davranan bir ülke olarak yukarıda belirttiğim hayalin gerçekleşmesi zor görünebilir. Fakat Fatih Projesi belirlenen takvimde uygulamaya geçirilebilirse belki de dünyada bu çapta dijital eğitime geçen ilk ülke olabiliriz. Bence ülke olarak bu fırsatı iyi değerlendirimeli ve özellikle %100 yerli kaynaklarla bu projenin hayata geçirilmesi için yapabileceklerimizi küçümsememeliyiz. 

NOT: Hindisatan teknoloji'nin eğitimde daha etkin kullanılması için çalışmalarına uzun süredir devam ediyor ve Aakash isimli devlet destekli tabletin geliştirmesinin bitmek üzere olduğu duyuruldu.  


Posted in: Mobile , Moodle  Tags:
aliozgur posted on August 10, 2011 12:36

We have been using Jira at our office for 5-6 years or so. During this time I was a member of the development team and was just an end user of Jira. After the recent change in my position I'm expected to use Jira as a management tool. Default installation of Jira comes with some defaults which will definitely help you but if you want to effectively manage your team and the job you have to fine tune your Jira setup.

Jira 4 Essentials by Patrick Li (Packt Publishing)  is a must read book if you need to fine tune and customize your Jira installation to meet your very own needs. The book walks through each customizable bit of Jira and with the Help Desk Project section at the end of each chapter customizations are applied to a practical sample implementation. I highly recommend team managers and Jira admins to read Jira 4 Essentials. 

JIRA 4 Essentials


Posted in: General Development  Tags:
aliozgur posted on August 9, 2011 10:13

Competition in the wild is really stressful and as a result people make hard to believe mistakes, especially when they are #2 not #1, such as claiming that the only real iOS app is theirs but not the one developed by the competitors. This kind of approach is technically wrong and has some ethical problems. Pricing, differentiation, offering more functionality, advertising your product, special offers, sponsorships, using social media and all other regular tools can be used in competition but blaming the competitors with sentences like "Do not get cheated by fake apps!!" (oh no!!! too many exclamations, this must be important) is not ethical.

Sentences like "My app is the only real iOS app" just reflects your technical inability and ignorance. Let me tell you the truth; the end user is not interested in what is real or fake (fake=browser  according to you). The end user just wants to get the advertised functionality. 

Anyway. Let me explain you,this is really simple, what makes an app a real iOS app

  1. Being approved by Apple and being available on the Apple AppStore
  2. Being able to run on iOS (iPhone, iPad and iPod Touch), which means your app executes real iOS machine code
  3. Following the iOS User Interface Design Guidelines
  4. Being able to use the official iOS APIs and Frameworks such as DocumentInteractionController found in UIKit Framework    

See? This is really simple just 4 rules not much or less. Including irrelevant app specific features and wrong performance indicators in a comparison table can make your conclusion seem convincing. But trust me users do not care much about these tables and conclusions especially if it is very clear that you have benefits from this comparisions.

NOTE-1: Browser apps are also real apps since they meet all the 4 criterias I mentioned

NOTE-2: mTouch and mTouch+ are not browser apps but they do have generic browser views to support displaying of unsupported Moodle content/mod/activity

NOTE-3: I'm aware of that the release of moodlEZ caused some uncontrolled stress on you. Take it easy and keep improving your apps and business


Posted in: Mobile , Moodle , MoodleTouch , MTouch  Tags:

Yesterday Yalla Apps contacted with me and asked for an interview. The interview  was conducted to get more insight on the WP7 developer community and thier opinions about different platforms.

Below are my answers to the questions of Yalla Apps

Yalla Apps: Are you a Developer or Designer or both? What is your experience level?

Ali Özgür : I'm a software developer. I currently work for Istanbul Bilgi University, one of the largest privately held university in Turkey, as the Platforms and Services Team Manager. I got BS degree in Computer Engineering from Istanbul Technical University and also hold an MBA degree from Istanbul Bilgi University. I'm developing software for more than 10 years. I've spend most of this time developing on Microsoft platforms with Microsoft developer tools. I've started my software development career working on Motorola MCU software. I've developed software with C++, Delphi, C# and ASP.NET MVC during my 10 year career. I worked on military, education, media, document management, OCR, workflow, Windows CE and mobile projects. I've contributed to some open source projects and in the mean time I maintain my own open source project PragmaSQL.

 

Yalla Apps: What gets you started on developing for a certain platform? What are all platforms you develop for?

Ali Özgür : Ecosystem of the platform is very important in my opinion. By ecosystem I mean developer tools, platform APIs and SDKs, programming model of the platform, the quality of the hardware running the platform, market share, general profile of the platform users, nice looking appstore There are also some technical parameters I take into consideration. For example providing a unified programming model to developers for different form factors, having strong DRM (Digital Rights Management) to allow just licensed software are some of the technical parameters. 

I'm developing software for Windows platform as part of my regular job with Microsoft .NET and other Microsoft technologies. Under PragmaTouch (my side project) we develop primarily for Apple iOS. Weare also evaluating Android and WP7 and have some demo apps. Personally I've also developed for Windows CE couple of years ago.

 

Yalla Apps: Would you consider developing for WP7? What you think is missing in WP7 development platform – what is better in others?

Ali Özgür: We are not just considering actually we are actively evaluating WP7 by writing some little demo apps. I think WP7 has a great development platform. First of all you build software for WP7 with the greatest development IDE in the market, in my opinion, which is Visual Studio. You develop with C#, which is the master piece of primarily Anders Hejlsberg and all other great guys at Microsoft. I really love C# as a programming language and when combined with Visual Studio you have the bare minimums to produce a quality software.  WP7 has an emulator not a simulator, the difference is somehow technical but important. As a developer in my opinion others have nothing better than the WP7 development platform. But as a platform for example copy/paste and hardware is better in iOS,

 

Yalla Apps: Do you think WP7 will play a significant role in mobile OS?

Ali Özgür : Yes, I definitely think that WP7 will play a significant role in mobile. Especially the recent Microsoft-Nokia agreement and the success of the partnership will be very important in determining the place of WP7 in mobile market. Nokia is the biggest mobile manufacturer by quantity and has high market shares in developing countries where demand for new technology is increasing every year. Xbox customers will also play important role during this process since Microsoft has great customer base on this platform.

 

Yalla Apps: Do you consider learning new technologies for mobile – which ones?

Ali Özgür : Yes, I consider learning new technologies for mobile. HTML5 is the number one in my personal list.


 


Posted in: .NET Development , IPhone , Mobile  Tags:

Here is a stackoverflow question which describes the issue very well

I have some code that needs to run after the a UIWebView finishes loading a document. For that I've set the UIWebView's delegate to my controller, and implemented the webViewDidFinishLoading method.

This gets called multiple times, depending on the type of page to load. I'm not sure if it's because of ajax requests, requests for images, or maybe even iframes.

Is there a way to tell that the main request has finished, meaning the HTML is completely loaded?

Or perhaps delay my code from firing until all of those events are done firing?

Some people say that "UIWebView must die". Yes I actually agree with them. UIWebView loads slower than Safari, it is hard to use and it does not expose some core methods. For example you can not get source of the loaded HTML page or the document title with a regular method call. But it has its strenghts like the stringByEvaluatingJavaScriptFromString (MonoTouch equivalent is EvaluateJavascript) method. With this method you can perform some of the missing core functions.

The idea to solve the mentioned problem goes on like this

 

  1. Inject javascript to the loaded (or still loading) document
  2. With the enjected javascript check the document ready state
  3. If document is already loaded inject  a hidden input indicating the document is loaded
  4. If document is not loaded yet inject another javascrip which simply binds an anonymous function to window.onload so that we can inject the hidden document loaded indicator input when window.onload is called
  5. As the last step each time didFinishLoading is called/fired try to find the injected document loaded indicator input element by evaluating another javascript
  6. If document loaded indicator input element is in place we can be sure that the whole document is loaded and we can continue with the execution
Here is the injected javascript script code mentiond through steps 1-4
 
if(document.readyState == 'complete')
{
	var element = document.createElement('input'); 
	element.setAttribute('type','hidden'); 
	element.setAttribute('id','moodlez_documentloaded'); 
	document.body.appendChild(element);
}
else
{
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.setAttribute('id','moodlez_windowload');
  script.text = "window.onload = function(){var element = document.createElement('input'); element.setAttribute('type','hidden'); element.setAttribute('id','moodlez_documentloaded'); document.body.appendChild(element);}";
  document.body.appendChild(script);
}

In the above JavaScript code the if(document.readyState == 'complete') block is needed so that we can handle the case when didFinishLoading fires only one time because the HTML page does not contain any frames and other stuff causing multiple  calls to didFinishLoading.

Here is the MonoTouch (C#) code which implements the steps mentioned above

 

public void LoadCompleted ()
{
	// Your code here......
	
	// check if the hidden document loaded indicator input is present
	jsResult = this.WebView.EvaluateJavascript ("document.getElementById('moodlez_windowload').toString();");
	
	// hidden element is not present so evaluate the javascript which has the potential to add the element
	if (String.IsNullOrWhiteSpace (jsResult)) 
	{
		string eval = "if(document.readyState == 'complete'){" + Helper.LoadCompleteJs + "}else{" + "var script = document.createElement('script');" + " script.type = 'text/javascript';" + " script.setAttribute('id','moodlez_windowload');" + " script.text = \"window.onload = function(){" + Helper.LoadCompleteJs + "}\";" + " document.body.appendChild(script);" + "}";				
		this.WebView.EvaluateJavascript (eval);
	}
	
	
	// Lets check again if the hidden document loaded indicator input is present
	jsResult = this.WebView.EvaluateJavascript ("document.getElementById('moodlez_documentloaded').toString();");
	
        // document loaded indicator input is not present so this means document did not complete loading	
	if (string.IsNullOrWhiteSpace (jsResult)) 
		return;
			
	// Your code here, which you want to be executed after document loading si really completed
			
}

Note: Helper.LoadCompleteJs static variable holds the following javascript code string which in turn is loaded from a resource file on application startup

 

var element = document.createElement('input'); 
element.setAttribute('type','hidden'); 
element.setAttribute('id','moodlez_documentloaded'); 
document.body.appendChild(element);

This method can be used from Objective-C, just translate the code of LoadComplete method to Objective-C and you are ready to go.

 


Posted in: MonoTouch  Tags:

Last week or so I had to perform a demo installation of our mobile Moodle web application mTouch-U  on a Windows 2003 Server with IIS 6 installed. I did know that it is possible to install ASP.NET MVC 3 application on IIS 6 but I had no hands on experience on that. As most of the devs who have to perform some sort of server installation I Googled a bit and found some resources. But to be honest none of the resource I've found and tried helped me much. Although most them were arranged as step-by-step guides sure they were missing something. Spending couple of hours with no success I decide to stop being lazy and decided to get my hands on the issue. Here is the steps I performed, I hope this post will not be one of these step-by-step guides missing something as well.    

  • Open the IIS Console
  • Select the Site (possibly Default Site) you will install your ASP.NET MVC 3 application, in our case that is mTouch-U
  • Right click and select New -> Virtual Directory from Context 
  • Specify mTouchU as the alias
  • Give the path to the mTouch-U binaries folder as the 
  • After creating the virtual directory select it and open up the context menu by right clicking. Select  Properties -> ASP.NET Page : Select 4.0... for ASP.NET version
  • In the same properties dialog open up the Virtual Directory Page  and click configure
    • Open up Mappings Page click 
    • Specify c:\windows\microsoft.net\framework\v4.0.30319\aspnet_isapi.dll as the 
    • Specify .mvc as the 
    • Verbs section specify Limit To : GET, HEAD, POST, 
    • Check "Script engine" 
    • Uncheck "Verify that file exists" 
  • Right click on Web Service Extensions in IIS Manager
  • Click on Allow all web service extensions for specific aplplication
  • In the application combo box see if ASP.NET 4 exists. If not exit this dialog without performin any action, if ASP.NET 4 exists do not follow the following steps
    • Right click on Web Service Extensions in IIS 
    • Click on Add new Web service 
    • Specify ASP.NET 4 as the extension name
    • Click on Add... on the right of Required files list
    • Specify c:\windows\microsoft.net\framework\v4.0.30319\aspnet_isapi.dll as "Path to file"
    • Check "Set extension status to allowed" click ok
  • Right click on mTouchU application in IIS Manager, select Properties from the context menu
  • Select Custom Errors page
  • Find 403;14 and select the item, then click to Edit button
  • Select URL as the "Message Type"
  • Specify /mtouchu/home.mvc/index as the URL value. When the user enters the base addrress to the broweser (i.e. http://www.domainname.com/m in our case) IIS 6 will automatically redirect the user to the Home controllers Index view.
That is it you will have your ASP.NET MVC 3 application running happily on IIS 6, I hope Smile

 


Posted in: .NET Development , ASp.NET MVC  Tags: