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:
which is consumed by this lambda method:
which is called from:
And creates these two files:
Note: for reference I’m still using the Util - REPL Script a Code Editor.h2
script which look like this:
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
which looks like this when opened:
and works by dragging-and-dropping a folder to ‘start a WebServer on’ in the top-left red box:
after the drop, a Cassini webserver will open up in the dropped folder (in this case on the 50878 port)
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:
which will now create the files inside an App_Code Folder:
A good way to confirm that this is working ok, is to add an error to the WebService code:
and reload the page:
Next step is to create an ASMX file:
on the web root folder:
which can be invoked from the browser :)
like the Login method:
which was successfully proxied into the ‘real’ webservice:
and can be confirmed by these two requests captured on fiddler:
the first to the proxy server:
the 2nd to the ‘real’ server (by the proxy server)
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):
Now that this is working, let’s refactor the asmx file creation into:
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:
is using the AccountManagement.asmx version hosted at the 15583 port:
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:
And now a login action, will generate two WebServices request (first to port 50874 and then to port 15583)
And since we proxied all methods, if I login and change the user’s password:
there will be a number of proxied calls (below in yellow is the ‘proxy call’, which is followed by the ‘real call’)
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