Tuesday 21 May 2013

Running the Asmx WebServices WebMethod invocation wrapper on a local WebServer (i.e Hacmebank UserManagement.asmx)

After the Creating an Lambda Method that creates an Asmx WebServices WebMethod invocation wrapper post, the next step is run the proxy class as a local webservice and consume it from HacmeBank.

Following from the code sample in the last blog post, I did a bit of refactoring so that the both files (the original WSDL C# file and the wrapper file) are saved on the same local folder.

Also the CSharp generation is now on a separate lambda method:


image

which is consumed by this lambda method:

image

which is called from:

image

And creates these two files:

image

Note: for reference I’m still using the Util - REPL Script a Code Editor.h2

image

script which look like this:

image

Since we will need to run this code on a web server, I going to use the Util - Start .NET WebServer on Local Folder.h2 tool

image

which looks like this when opened:

image

and works by dragging-and-dropping a folder to ‘start a WebServer on’ in the top-left red box:

image

after the drop, a Cassini webserver will open up in the dropped folder (in this case on the 50878 port)

image

since the wsTest is going to be the root of our site, we actually want the C# files to be on an App_Code folder, which can be achieved with this code change:

image

which will now create the files inside an App_Code Folder:

image
image
image

A good way to confirm that this is working ok, is to add an error to the WebService code:

image

and reload the page:

image

Next step is to create an ASMX file:

image

on the web root folder:

image

which can be invoked from the browser :)

image

like the Login method:

image

which was successfully proxied into the ‘real’ webservice:

image

and can be confirmed by these two requests captured on fiddler:

image

the first to the proxy server:

image

the 2nd to the ‘real’ server (by the proxy server)

image
image

Note that I had to make a small change to the proxy code in order to capture it on the local proxy (i.e. add an extra . to the http://localhost address):

image

Now that this is working, let’s refactor the asmx file creation into:

image
image

Finally we need to wire this into the action working live site (i.e make it consume our proxied webservice vs the real one)

At the moment the site:

image

is using the AccountManagement.asmx version hosted at the 15583 port:

image

but, what we want is to use the version at http://localhost:50874/_wsTest/UserManagement.asmx

So let’s edit this web.config file to use the proxied version:

image

And now a login action, will generate two WebServices request (first to port 50874 and then to port 15583)

image

And since we proxied all methods, if I login and change the user’s password:

image

there will be a number of proxied calls (below in yellow is the ‘proxy call’, which is followed by the ‘real call’)

image

Which is exactly what we wanted to do, since now all webservice’s traffic is going through the ‘ast generated proxy method’  :)

Script used in this post

1) create AST proxy method, asmx file and save them in local folder:
   1: var compilationUnit = new CompilationUnit();

   2:              

   3: compilationUnit.add_Using("System"); 

   4: compilationUnit.add_Using("System.Web.Services"); 

   5:  

   6: Action<TypeDeclaration, string, TypeDeclaration> add_Property_To_Type_Constructor = 

   7:     (targetType, propertyName, propertyType) =>

   8:         {

   9:             targetType.add_Property(propertyName,propertyType)    

  10:                       .add_Ctor()                                

  11:                       .body()                                    

  12:                       .add_Assignment(propertyName, propertyType);

  13:         

  14:         };

  15:  

  16: Func<MethodDeclaration,string, MethodDeclaration> create_ProxyMethod = 

  17:     (methodToProxy, webServicesObjectName) =>

  18:         {            

  19:             var proxyMethod = methodToProxy.clone()

  20:                                            .remove_Attributes();

  21:             var body = proxyMethod.add_Body();        

  22:             

  23:             proxyMethod.add_Attribute("WebMethod");

  24:             

  25:             var parameters = methodToProxy.parameters().names().ast_Identifiers().ToArray();

  26:             var invocation = webServicesObjectName.ast_Invocation_onType(methodToProxy.Name,parameters);

  27:             

  28:             if(proxyMethod.TypeReference.name() =="void" || proxyMethod.TypeReference.name() == "System.Void")

  29:             {

  30:                 body.append(invocation.expressionStatement());

  31:             }

  32:             else

  33:             {

  34:                 var result = body.add_Variable("result", invocation, methodToProxy.TypeReference);

  35:                 body.add_Return(result.Name.ast_Identifier());

  36:             }

  37:             return proxyMethod;

  38:          }; 

  39:  

  40:  

  41: Func<TypeDeclaration,string, string> create_Wrapper_CSharpCode = 

  42:     (wsClass, wsFileName)=> 

  43:         {

  44:             var wrapperType  = compilationUnit.add_Type(wsClass.Name + "_Wrapper");

  45:             var propName = "_web_Service";

  46:             add_Property_To_Type_Constructor(wrapperType,propName, wsClass);

  47:             

  48:             var wsMethods = wsClass.methods_with_Attribute("System.Web.Services.Protocols.SoapDocumentMethodAttribute");

  49:             foreach(var wsMethod in wsMethods)

  50:             { 

  51:                 wrapperType.append(create_ProxyMethod(wsMethod,propName));      

  52:             }

  53:             var csharpCode = compilationUnit.csharpCode()

  54:                         .insertAt(0, @"//O2File:{0}".format(wsFileName).line());;

  55:             return csharpCode;

  56:         };

  57:  

  58: Action<string,string> create_Wrapper_SourceCodeFile = 

  59:     (sourceFile, targetFile)=>

  60:         {

  61:             var fileAst = sourceFile.csharpAst();

  62:             var _wsClass = fileAst.type_with_BaseType("System.Web.Services.Protocols.SoapHttpClientProtocol");  

  63:             var _csharpCode = create_Wrapper_CSharpCode(_wsClass, sourceFile.fileName());

  64:             _csharpCode.saveAs(targetFile);

  65:         };                    

  66:  

  67: Action<string,string> createAsmxFile = 

  68:     (className, targetFile)=>

  69:         {

  70:             var asmxCodeContent = @"<%@ WebService Language=""c#"" Class=""{0}"" %>"

  71:                                        .format(className);

  72:             asmxCodeContent.saveAs(targetFile);

  73:         };

  74:         

  75: var sourcefile = @"E:\O2\O2.Temp\5_10_2013\wsdl_tmpC5E1\WS_UserManagement.cs";

  76:  

  77: var webRoot_Folder = "_wsTest".tempDir(false);

  78: var appCode_Folder = webRoot_Folder.pathCombine("App_Code").createDir();

  79: var wsdlfile = sourcefile.file_Copy(appCode_Folder);

  80: var wrapperFile = appCode_Folder.pathCombine("_WebMethod_" + wsdlfile.fileName());

  81:  

  82: var asmxFile = webRoot_Folder.pathCombine("UserManagement.asmx");

  83: createAsmxFile("WS_UserManagement_Wrapper", asmxFile);

  84:  

  85: create_Wrapper_SourceCodeFile(wsdlfile, wrapperFile);                        

  86:  

  87: codeEditor.open("").open(wrapperFile);

  88:  

  89: if (true)

  90:     codeEditor.compileCSSharpFile();

  91:         //      .executeFirstMethod();

  92:               

  93: //codeEditor.set_Text(compilationUnit.csharpCode(), ".cs");

  94: return "done";

  95:   

  96: //using ICSharpCode.NRefactory.Ast

  97: //using O2.API.AST.ExtensionMethods.CSharp

  98: //O2File:_Extra_methods_To_Add_to_Main_CodeBase.cs