How to configure a proxy class for an ASP.NET web service for flexible deployment to production
I inherited a web app at the Visual Studio 2003 level that placed all of its code for accessing SQL server in an ASMX web service. This web project had a web reference to the web service. I needed to bring the whole thing under source control, upgrade it to Vstudio 2008 and make a bunch of fixes and enhancements.
In doing this, I came across a neat article from Code Magazine emphasizing the advantages of "assembly separation". It was written for WCF but it "inspired me" to:
- remove the web reference from my main ASP.NET web application project
- add a new project as a class library which I called ProxyZipeeeService
- add a web reference in the ProxyZipeeeService project to point at the ZipeeeService project
- add a reference in the main web app project to ProxyZipeeeService.DLL produced by building the project of the same name.
The things work and I guess there are some [performance?] advantages to separating things out like this but having described my structure, I need to get to my question/problem:
I run into lots of configuration problems when I deploy this into production that require me to make changes that are quite "awkward" and prone to me screwing things up. Here is my guess about what needs changing but I've searched extensively and cannot understand how:
The ProxyZipeeeService project with the web reference in it produces files as follows:
- Reference.map.vb, ProxyZipeeeService.disco, ProxyZipeeeService.wsdl and app.config
- on my development PC, the app.config file produced settings for the URL of localhost (as it should for my PC). Please view this XML entry at: http://pastebin.com/JtQCxT73
When I publish the web application project to the production web server, the URL for the webservice is "buried" inside the DLL for ProxyZipeeeService (which at this time is in the bin folder of the web app because it is referenced).
Because the prod web server is configured to recognize "host header files" [another question someday], the URL with localhost fails with a HTTP 400 Bad Request. The host header config requires anything related to this default website to use the domain http://www.zipeee.com/ZipeeeWebService/Zipeee.asmx
So to fix this, I have been having to "dismantle" my development project for ProxyZipeeeService - completely deleting the web reference, adding it back but this time make the dialog point to the WS on the production server (instead of letting it find the WS in "this solution" because that results in the problematic "localhost" setting).
Eventually I am able to push out to the prod server a web project referencing the proxy dll that won't run into this host header issue and it works without throwing the HTTP 400 error.
But there has to be a better way!
In short, the critical proxy dll cannot be configured with regard to the URL it should use the way I'm set up now. I've tried putting the applicationSettings entry from the app.config into the web.config of my web application project. I've also tried putting a variation on this into the appSettings section. Both of these attempts fail.
I hope I have been clear and not been too verbose. Please do not suggest major surgery like WCF because I can't bite off on that now for this project. Thank you for reading and thanks in advance for your help.
EDIT UPDATE: Changing URL in web app's WEB.CONFIG is not detected! Problem remains. Here is what I did:
- Followed exactly what you said to do, lifting the settings from the app.config of the proxy to the web.config of the web app (establishing a new configuration section group that points to my setting from app.config.
- The value in the proxy and now also in web.config reads as: http://localhost/ZipeeeWebService/Zipeee.asmx which is fine for testing on my dev PC
- Before deploying all this to the production server, I thought I should test a bit. My first test was with the settings above and I set a breakpoint in the web service project and verified that the proxy had indeed come to localhost as the web.config entry intended and as expected.
- Next (test case 2) I changed the web.config entry from localhost to www.zipeee.com which is where the production webservice the public facing web app uses.
- I left the same breakpoint in the first web service call in place (expecting that it would not be hit because the intention was to use the URL specified in the web.config)
- To my surprise, the breakpoint was hit and when I examined the URL via the Immediate Window, it showed it to be localhost (should have been to www.zipeee.com as desired in web.config).
Perhaps I have misunderstood what this approach should allow? Is there something I am missing? I did NOT rebuild the Proxy DLL (that remains with localhost) which I thought was the whole intent (i.e. to be able to control the URL in a sort of "late-binding" way via changes to the web.config of the web app).
I remain stumped. Hopefully, you could help me a bit more...Thanks.
EDIT UPDATE: 12 Oct
Thanks - I read your notes but I'm still confused. The ProxyZipeeeService project code is all generated from the web reference. Here is a snippet from the reference.vb file (are you suggesting I modify this generated code?):
Public Sub New()
MyBase.New
Me.Url = Global.ProxyZipeeeService.My.MySettings.Default.ProxyZipeeeService_WSZipeee_Zipeee
If (Me.IsLocalFileSystemWebService(Me.Url) = true) Then
Me.UseDefaultCredentials = true
Me.useDefaultCredentialsSetExplicitly = false
Else
Me.useDefaultCredentialsSetExplicitly = true
End If
End Sub
Public Shadows Property Url() As String
Get
Return MyBase.Url
End Get
Set
If (((Me.IsLocalFileSystemWebService(MyBase.Url) = true) _
AndAlso (Me.useDefaultCredentialsSetExplicitly = false)) _
AndAlso (Me.IsLocalFileSystemWebService(value) = false)) Then
MyBase.UseDefaultCredentials = false
End If
MyBase.Url = value
End Set
End Property
By the way, could you comment on whether the whole idea of a separate assembly (proxy) for a web service is even a worthwhile thing. There may be some performance benefits (?) but these configuration issues are giving me fits.
EDIT-UPDATE 12 Oct - a bit later
After the last posting of the code from the generated file reference.vb, I spotted the problem! The declarations you had me place in the web app's web.config file were named:
section name="ProxyZipeeeService.Properties.MySettings"
while the reference.vb file refered to the setting as:
Me.Url = Global.ProxyZipeeeService.My.MySettings.Default.ProxyZipeeeService_WSZipeee_Zipeee
Changing the web config n开发者_运维百科ame to read as section name="ProxyZipeeeService.My.MySettings" has enabled the proxy to find the setting in the web app's web.config and I'm now able to "toggle" the web service URL through configuration parameters.
Thank you so much for your help. I am closing this now.
p.s. Do the "professionals" use Proxy classes as wrappers for web services like this?
You should place the configuration in the web.config of you web app, making a section group that references back to your ProxyZipeeeService project. To do so, copy both the sectiongroup and the actual applicationSettings from your ProxyZipeeeService to your web application:
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="ProxyZipeeeService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<!--other stuff-->
<applicationSettings>
<ProxyZipeeeService.Properties.Settings>
<!--your original appSettings-->
</ProxyZipeeeService.Properties.Settings>
</applicationSettings>
Then you can change the settings after your application has been deployed.
If all else fails, you could also make your ProxyZipeeeService library expose the URL as a public property, so it can be changed at runtime by the web application calling it.
I hope this was helpful.
精彩评论