Showing posts with label T4. Show all posts
Showing posts with label T4. Show all posts

Monday, 7 January 2013

Async WCF interface with T4

T4 template that takes a DLL, pulls out all the WCF interfaces and gives your client development team a proxy class to code against.

namespace ServerInterfaces
{
[ServiceContract]
public interface ILoginFacade
{
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
Method = "GET", UriTemplate = "/Login")]
GetLoginResponse GetLogin()

[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
Method = "PUT", UriTemplate = "/Login")]
UpdateLoginResponse UpdateLogin(UpdateLoginRequest request);

[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
Method = "GET", UriTemplate = "/Login/WriteToLog")]
void WriteToLog();
}

[ServiceContract]
public interface ITradeFacade
{
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
Method = "PUT", UriTemplate = "/Trades")]
int UpdateTradesDatabase(string userId);
}
}

Generated Client Proxy

   
/***************************************************************************************
**** GENERATED CODE: Use t4toolbox & tangiblet4editor to update AsyncInterfaces.tt ****
****************************************************************************************/
using System;
using Newtonsoft.Json;

namespace WcfServiceDirectory
{
public partial class Services
{
public Services()
{
this.LoginFacade = new LoginFacade();
this.TradeFacade = new TradeFacade();
}

public LoginFacade LoginFacade { get; set; }
public TradeFacade TradeFacade { get; set; }
}

public class LoginFacade
{
private IServiceExecutor serviceExecutor;

public LoginFacade() { this.serviceExecutor = new ServiceExecutor(); }

public void GetLogin(Action<CallCompleteEventArgs<DTOs.GetLoginResponse>> callback)
{
serviceExecutor.Get<DTOs.GetLoginResponse>("/Login", callback);
}

public void UpdateLogin(DTOs.UpdateLoginRequest request, Action<CallCompleteEventArgs<DTOs.UpdateLoginResponse>> callback)
{
serviceExecutor.Put<DTOs.UpdateLoginResponse>("/Login", JsonConvert.SerializeObject(request), callback);
}

public void WriteToLog(Action<CallCompleteEventArgs<Object>> callback)
{
serviceExecutor.Get<Object>("/Login/WriteToLog", callback);
}
}

public class TradeFacade
{
private IServiceExecutor serviceExecutor;

public TradeFacade() { this.serviceExecutor = new ServiceExecutor(); }

public void UpdateTradesDatabase(System.String userId, Action<CallCompleteEventArgs<System.Int32>> callback)
{
serviceExecutor.Put<System.Int32>("/Trades", JsonConvert.SerializeObject(userId), callback);
}
}
}

Core REST service execution code

namespace ClientProxy
{
public interface IServiceExecutor
{
void Get<TResponse>(string uriTemplate, Action<CallCompleteEventArgs<TResponse>> callback);
void Put<TResponse>(string uriTemplate, string request, Action<CallCompleteEventArgs<TResponse>> callback);
}

public class ServiceExecutor : IServiceExecutor
{
ServiceEnvironment serviceEnvironment = new ServiceEnvironment() { UseHttpS = false, BaseAddress = "localhost", Port = 52802 };

public void Get<TResponse>(string uriTemplate, Action<CallCompleteEventArgs<TResponse>> callback)
{
var client = new WebClient();
var address = GetUri(uriTemplate);
client.DownloadStringCompleted += (sender, eventArgs) =>
{
if (callback == null) return;
var response = JsonConvert.DeserializeObject<TResponse>(eventArgs.Result);
callback(new CallCompleteEventArgs<TResponse>(response, eventArgs));
};
client.DownloadStringAsync(address);
}

public void Put<TResponse>(string uriTemplate, string request, Action<CallCompleteEventArgs<TResponse>> callback)
{
var client = new WebClient();
var address = GetUri(uriTemplate);
client.UploadStringCompleted += (sender, eventArgs) =>
{
if (callback == null) return;
var response = JsonConvert.DeserializeObject<TResponse>(eventArgs.Result);
callback(new CallCompleteEventArgs<TResponse>(response, eventArgs));
};
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.UploadStringAsync(address, "PUT", request);
}

private Uri GetUri(string uriTemplate)
{
var uriString = string.Format("http{0}://{1}:{2}/Facades{3}",
serviceEnvironment.UseHttpS ? "s" : "",
serviceEnvironment.BaseAddress,
serviceEnvironment.Port,
uriTemplate);
return new Uri(uriString);
}
}
}

Source code


The solution features:



  • DTOS:  A portable class library project containing DTOs
  • Interfaces:  A class library containing the WCF interfaces.  This project also contains the T4 template scripts
  • WCF ServiceDirectory:  A Silverlight project which calls the rest services , contains REST service calling code.
  • A website project with Web API (WCF) REST Services

https://github.com/stevenh77/AsyncServiceInterfaces

Monday, 23 January 2012

T4 Example: Code Generation

This simple T4 example shows how to generate a C# enum class from an external resource, in this case a SQL database.

First of all, let’s create our database:

USE [master]
GO

CREATE DATABASE [T4Demo]
GO

USE [T4Demo]
GO

CREATE TABLE [dbo].[AssetClass](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Description] [varchar](50) NOT NULL,
CONSTRAINT [PK_AssetType] PRIMARY KEY CLUSTERED ( [Id] ASC )
)
GO

INSERT [AssetClass] VALUES ('Equity');
INSERT [AssetClass] VALUES ('Fixed Income');
INSERT [AssetClass] VALUES ('Cash');
GO

Next we’ll create a C# console application and add a T4 text template file:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.IO" #>

public enum <#= Path.GetFileNameWithoutExtension(Host.TemplateFile) #>
{
<#
if(Validate())
{
BuildEnum();
}
#>
}

<#+

private bool Validate()
{
if(string.IsNullOrEmpty(Server)) { Error("No server was specified"); }
if(string.IsNullOrEmpty(Database)) { Error("No database was specified"); }
if(!IntegratedSecurity)
{
if(string.IsNullOrEmpty(User)) { Error("No user id was specified"); }
if(string.IsNullOrEmpty(Pwd)) { Error("No password was specified"); }
}

if(string.IsNullOrEmpty(Table)) { Error("No table was specified"); }
if(string.IsNullOrEmpty(ValueColumn)) { Error("The value column was specified"); }
if(string.IsNullOrEmpty(TextColumn)) { Error("The text column was specified"); }

return !this.Errors.HasErrors;
}

private void BuildEnum()
{
using (SqlConnection conn = new SqlConnection(BuildConnStr()))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = string.Format(
"select {0}, {1} from {2}",
ValueColumn,
TextColumn,
Table);
cmd.CommandType = System.Data.CommandType.Text;

conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();

PushIndent("\t");
while (rdr.Read())
{
string enm = string.Format("{0} = {1},",
CreateValidIdentifier(rdr[TextColumn].ToString()),
rdr[ValueColumn].ToString());
WriteLine(enm);
}

WriteLine("Unknown = 0");
PopIndent();
rdr.Close();
conn.Close();
}
}

// Strips spaces and full stops
private string CreateValidIdentifier(string input)
{
string pattern = @"[\.\[\]\s]";
Regex regex = new Regex(pattern, RegexOptions.None);
return regex.Replace(input, "");
}

private string BuildConnStr()
{
SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();
csb.DataSource = Server;
csb.InitialCatalog = Database;
csb.IntegratedSecurity = IntegratedSecurity;

if(!IntegratedSecurity)
{
csb.UserID = User;
csb.Password = Pwd;
}

return csb.ConnectionString;
}

private string Server = ".";
private string Database = "T4Demo";
private bool IntegratedSecurity = true;
private string User = "";
private string Pwd = "";
private string Table = "dbo.AssetClass";
private string ValueColumn = "Id";
private string TextColumn = "Description";

#>

Now save the file and you'll have your own up-to-date enum class driven from your database:

public enum AssetClass
{
Equity = 1,
FixedIncome = 2,
Cash = 3,
Unknown = 0
}

You can also set up Visual Studio to always regenerate the file on each build if you prefer.


Source code:  http://stevenhollidge.com/blog-source-code/T4CodeGenerationEnums.zip