web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :

Android Ax App – Part 1–Set up the intermediate WCF service

Shashi s Profile Picture Shashi s 1,203

I came across a blog by Joris De Gruyter http://daxmusings.blogspot.com/2011/11/10-minute-app-windows-phone-7-app.html and decided to use that to connect to an Android device.

This is part 1 of 2 to explain the process of creating the Android application to connect to Ax via AIF services.

Unlike the blog mentioned above, I had to enable REST in the WCF service, and output it as JSON. This is because android has a better JSON support than SOAP (ksoap can be used to consume the WCF services, but I have found JSON to be a much easier approach)

To enable REST services, I installed the WCFRestContrib package. This is available from NuGet and can be installed using

PM> Install-Package wcfrestcontrib

We can create the WCF Service using the no configuration mode. This link defines how to create a WCF service with no configuration. Which means most of the web.config is deleted, and another identifier is attached to the SVC file. This however relies of transport security as there is no SOAP envelope around this. WCFRESTContrib allows to create a custom authentication system. The authentication data can be retrieved from the HTML headers and verified.

So the WCF service should look like this, it enables a GET method and has a certain URI, and outputs the data in JSON

namespace WcfService1
{
  [ServiceContract]
  [ServiceAuthentication] //WCFRESTContrib attribute - authentication per session (or at method level for per call) public interface IApi1 {
  [WebGet(UriTemplate = "/api1/appName", ResponseFormat = WebMessageFormat.Json)]
  [OperationContract]
  string ApplicationName();

  [WebGet(UriTemplate = "/api1/items", ResponseFormat = WebMessageFormat.Json)]
  [OperationContract]
  List GetAllItemIds();
}
}

The Service interface markup (this allows for a noconfiguration WCF Service)

<%@ ServiceHost 
    Language="C#" 
    Debug="true" 
    Service="WcfService1.Api1" 
    CodeBehind="Api1.svc.cs"
    Factory="System.ServiceModel.Activation.WebServiceHostFactory"
    %>

The Service file itself

namespace WcfService1
{
    [WebAuthenticationConfiguration(
    typeof(WcfService1.ApiAuthnetication),
    typeof(ApiAuthneticationValidator),
    true,
    "My Application")]
    public class Api1 : IApi1 {
    public string GetUsername()
    {
        object authValue;
        string authStr = "", username = "", password = "";
        try {
            var keys = OperationContext.Current.IncomingMessageProperties.Keys;
            OperationContext.Current.IncomingMessageProperties.TryGetValue("httpRequest", out authValue);
            if (authValue != null)
            {
                System.ServiceModel.Channels.HttpRequestMessageProperty p = (System.ServiceModel.Channels.HttpRequestMessageProperty)authValue;
                authStr = p.Headers.Get("Authorization");
                ApiAuthnetication.GetUsernamePwd(authStr, out username, out password);
            }
        }
        catch (Exception e)
        {
            return e.Message;
        }
        return username;
    }
    public string ApplicationName()
    {
        string username = this.GetUsername();

        return username;
    }
    public List GetAllItemIds()
    {
        return Item.GetItems(this.GetUsername());
    }
    }
}

Notice the header attributes. This needs to be defined and is based on the WCFRESTContrib package. The authentication classes created is. Notice that the Username and password are being sent in the header with the tag “Authorization” this can be renamed to anything you like

namespace WcfService1
{
    public class ApiAuthnetication : WcfRestContrib.ServiceModel.Dispatcher.IWebAuthenticationHandler {
    public static bool GetUsernamePwd(string authenticationStr, out string username, out string password)
    {
        bool result = true;
        username = "";
        password = "";
        try {
            var values = authenticationStr.Split(':');
            username = values[0];
            password = values[1];
        }
        catch {
            result = false;
        }
        return result;
    }

    public System.Security.Principal.IIdentity Authenticate(
            System.ServiceModel.Web.IncomingWebRequestContext request,
            System.ServiceModel.Web.OutgoingWebResponseContext response,
            object[] parameters,
            System.IdentityModel.Selectors.UserNamePasswordValidator validator,
            bool secure,
            bool requiresTransportLayerSecurity,
            string source)
   {
       string authHeader = "";
       string userName = "";
       string password = "";
       if (request.Headers.HasKeys() == true && request.Headers.AllKeys.Contains("Authorization") == true)
       {
           authHeader = request.Headers.Get("Authorization");
           //var values = authHeader.Split(':');
           //userName = values[0];
           //password = values[1];
           GetUsernamePwd(authHeader, out userName, out password);
       }
       validator.Validate(userName, password);
       return new GenericIdentity(userName, this.GetType().Name);
   }
}

   public class ApiAuthneticationValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
   {
       public override void Validate(string userName, string password)
       {
          //Do your custom authentication here
          if (userName.Equals("claimguy@myapp.com", StringComparison.InvariantCultureIgnoreCase) == false
                  || password.Equals("claimguy@myapp.com", StringComparison.InvariantCultureIgnoreCase) == false)
              throw new Exception("Authentication Failed");
       }
   }
}

The code to get the InventTable data is pretty similar to Joris’s blog. Here is mine:

namespace WcfService1
{
    public class Item {
        public string ItemId { get; set; }
        public string Name { get; set; }

        public static List GetItems(string username)
        {
            List items = new List();
            string itemIdFrom = "1000"; //I cheated here 
            string itemIdTo = "1105";   //I cheated here again 
            //Fetch items from AX here 
            using (ItemService.ItemServiceClient client = new ItemService.ItemServiceClient())
            {
                ItemService.QueryCriteria qc = new ItemService.QueryCriteria();
                ItemService.CriteriaElement criteria = new ItemService.CriteriaElement();
                criteria.DataSourceName = "InventTable";
                criteria.FieldName = "ItemId";
                criteria.Operator = ItemService.Operator.Range;
                criteria.Value1 = itemIdFrom;
                criteria.Value2 = itemIdTo;
                qc.CriteriaElement = new ItemService.CriteriaElement[] { criteria };

                ItemService.CallContext context = new ItemService.CallContext();
                context.Company = "ceu";
                context.MessageId = Guid.NewGuid().ToString();
                context.LogonAsUser = string.Format("LoonAx\\{0}", username);

                var axItems = client.find(context, qc);
                if (axItems.InventTable != null)
                {
                    foreach (var inventTable in axItems.InventTable)
                    {
                        Item item = new Item() { ItemId = inventTable.ItemId, Name = inventTable.NameAlias };
                        items.Add(item);
                    }
                }
            }
            /* //Mocking for AIF
            for (int i = 0; i < 10; i++) { Item item = new Item() { ItemId = (1000 + i + 1).ToString(), Name = (1000 + i +          1).ToString() + " - name" }; items.Add(item); }*/ return items;
        }
    }
}

To make the connection secure (since we are sending the authentications via plain text in the HTML headers, this service should ideally be secure)

In the next blog I will go through the Android app to consume this service


Filed under: .Net, Android, Ax 2012, Dynamics Ax, JSON, REST, WCF Tagged: Android, AX2012, JSON, REST, WCF

This was originally posted here.

Comments

*This post is locked for comments