Relocating an app.config config section to the AppData folder - c#

I have a Windows Forms application that connects to a web service that is configured in the app.config under the typical configuration\system.serviceModel\client\endpoint node like so:
<system.serviceModel>
<bindings>
...
</bindings>
<client>
<endpoint address="http://blahblah/service.asmx" ... />
</client>
</system.serviceModel>
This application is often used on fairly locked down Windows systems, such that administrator rights are required (typically via UAC) to modify any files within the Program Files directory in which the application is installed. That is fine for most configuration, as it should not be user configurable.
I would like to relocate the endpoint configuration to the user's app data folder, so that this can be modified at a later date, post installation, and without any administrator intervention.
I understand I can use the configSource attribute of the client element under system.serviceModel to point to a separate config file however this does not seem to support absolute paths (let alone ideally also the appdata environment variable), and hence does not appear to be an option for pointing to appdata.
My question therefore is, how can I relocate this configuration block to an external file in the user's appdata folder where it can be modified without subsequent administrator intervention whilst leaving the rest of the configuration securely in the program files installation folder?

You need "externalize" your <client> section like this:
Move the contents of your <client> section to a new file, e.g. `~/App_Data/Config/Client.config":
<client>
<endpoint address="http://blahblah/service.asmx" ... />
</client>
Modify our existing config to point to that externalized config file:
<system.serviceModel>
<bindings>
...
</bindings>
<client configSource="/App_Data/Config/Client.config" />
</system.serviceModel>
Now, you can modify our client settings in that external file, without having to touch the main web.config file anymore.
Just word of caution: while changing the web.config also automatically causes the IIS application pool to recycle (and thus reload the new config), this is no longer the case when you modify such an externalized config file. So you'll need to explicitly recycle the IIS app pool to get the new settings reloaded from your config file

Related

Hosting WCFService Library on IIS 10 with SSL encryption

I am trying to host a WCF Service Library on IIS 10, with a self signed SSL.
To Obtain Minimum Complete Verifiable Example, Open Visual studio 2017
New>Project>C#>Web>WCFLibrary With this you will get a simple code that has one operation contract which takes an integer and returns a string.
Now I am trying to host this on IIS with Self Signed SSL (Mine has more operation contract but this will do).
What I have tried so far.
Now the next part is hosting it on IIS, so I created the SVC file
My SVC file contains ->
<%# ServiceHost Language = "C#" Debug = "true" Service = "WcfServiceLibrary2.Service1" %>
Then all the tutorials that I can find edit Web.Config, which is unavailable in Visual Studio 2017, so I tried two things
1. Created a Web.Config file and added the configurations
2. Published the website and then obtained Web.Config which did not require any changes
Then I went on to IIS (as administrator) and added a new website
Then while trying to browse, to see the message that IIS service is hosted I got this error "Cannot read configuration file" To Solve this I followed success.trendmicro.com/…
Now that error is gone but now I am getting
To solve this I Followed
IIS - 401.3 - Unauthorized But this lead to the browser letting me browse the directories rather than giving the message that a Service has been created.
Any Idea what I am missing here?
Definitely I am missing something major here as I have failed to host it on HTTP itself, All the tutorials I find online have a file Web.Config and not App.config, I am looking for an example (preferably with Images) that demonstrate it just with this small example.
I know this doesn't follow all SO guidelines on asking questions, but I have failed to articulate it into a question that does.
Edit
As per LexLi's advice that it may already be hosted, I went and tried to consume it using svcutil which gave me the error
WS-Metadata Exchange Error
URI: http://localhost/Service1.svc
Metadata contains a reference that cannot be resolved: 'http://localhost/Service1.svc'.
The remote server returned an unexpected response: (405) Method Not Allowed.
The remote server returned an error: (405) Method Not Allowed.
HTTP GET Error
URI: http://localhost/Service1.svc
There was an error downloading 'http://localhost/Service1.svc'.
The request failed with HTTP status 404: Not Found.
The Url is correct because I obtained it by using the browse functionality from IIS.
First, please don’t set the IIS physic path to desktop, which will cause the permission problem. we could set the IIS site physical path to the folder under C partition.
Second, please read the following link, which mainly indicates that WCF service library project could not published directly to IIS since its Appconfig could not be recognized by IIS unless additional Webconfig is added manually in the root directory of the web site.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/deploying-a-wcf-library-project
Generally speaking, we use the WCF service project template which contains an auto-generated Webconfig file instead of WCF service library project template, since it is generally used as a class library.
By default, the service is hosted with BasicHttpBinding, it depends on the following tag.
<protocolMapping>
<add binding="basicHttpBinding" scheme="http" />
</protocolMapping>
The service could also be configured manually by the following ways. These two ways configuration file is equivalent.
<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="mybehavior">
<endpoint address="" binding="basicHttpBinding" contract="WcfService1.IService1" bindingConfiguration="mybinding"></endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="mybinding">
<security mode="None">
</security>
</binding>
</basicHttpBinding>
</bindings>
It is unnecessary to assign the service endpoing address in the webconfig. It should be completed in the IIS site binding module.
WCF System.ServiceModel.EndpointNotFoundException
At last, we could host the service over https by adding an additional service endpoint, refer to the following configuration(simplified configuration).
<protocolMapping>
<add binding="basicHttpBinding" scheme="http"/>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
then add the https protocol in IIS site binding module.
Configuring Web.config to publish WCF Service
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-an-iis-hosted-wcf-service-with-ssl
Feel free to let me know if there is anything I can help with.
First Credit where credit is due, many of the issues I was pointed in the right direction by multiple SO users to name a few would be: Mikael bolinder, Abraham Qian, Lex Li, the wonderful people in the C# chat room and a co-worker of mine(Doesn't have an account on SO as of writing this answer), In this answer I plan to cover everything you might need to host a WCF Library in IIS Server using HTTPS security.
Tools I used:
Visual Studio 2017 professional
IIS 10 (Comes with windows 10 but has to be activated in windows features ) (See below)
First:
Make sure you have all the components you will need from visual studio installed.
Windows -> .Net Desktop Development
Windows -> Universal Windows platfor development
Web & Cloud -> ASP.NET and web development
In this list and among other list that will come, some extra components may be included, the reason for that is I installed them and couldn't verify one way or the another if they are absolutely necessary.
Now, let's add the windows features necessary. Control Panel -> Programs -> Turn Windows features on or off
Make sure to go into WCF Services and check HTTP Activation, don't be fooled by the square block (One of my mistakes)
Now let's get to creating the Service. Open Visual Studio File -> New -> Project -> Visual C# -> Web -> WCF -> WCF Service Library This generates the MCVE that you are trying to host
Now you have to link it with a website in order to generate the Web.Config file along with the SVC file, to do that, On Solutions Explorer, right click on your solution, Add-> New Website.
Now in the web.config file add
<system.serviceModel>
<services>
<service name="WcfServiceLibrary4.Service1"> <!-- Change the library name as per your need -->
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="WcfServiceLibrary4.IService1"/> <!-- Change the library name as per your need -->
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Next add reference to service on the website
Discover services and add the service you have created. Now Build your solution and publish it. **Careful Don't publish the solution in a user Directory like Desktop or documents or else ACL permissions will give you a headache, rather publish it directly in a directory in Drive.
Now Hosting time
First lets open IIS (Always as admin) and create a new certificate.
On the server go to the IIS part and Select Server Certificates, then click create new certificate on the right end.
Now create a new website from the left menu
Make sure to switch to https and select your certificate here, Now to verify that your service is created you will need to browse your websites svc file created, sadly at this point you will get an error saying Server Error in '/' Application.
Could not find a base address that matches scheme http for the endpoint with binding BasicHttpBinding. Registered base address schemes are [https]. I was unable to find the cause of the error, but I was able to find a bypass of it,
Steps to bypass this error -> Select you website from the menu on the left, on the menu at the right click bindings and also add an HTTP binding, with a different port.
After this you will be able to browse the HTTPS version of your svc file.
Now if you browse the HTTPS link you get the message that the service is created
Now you can go Ahead and create an application that consumes this service.
What lies ahead
I will try to find a way to do this without adding an additional binding
The Second goal would be to achieve this without adding the extra website.
If and when I achieve these I will update, however these are not my priority right now and may not be added for quite a while, if anything didn't make sense, or you have any ideas of improvement comment below.
In short here are the steps :
Create Self-Signed Certificate
Add SSL Binding
Configure Virtual Directory for SSL
Configure WCF Service for HTTP Transport Security
This link is more in depth : https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-an-iis-hosted-wcf-service-with-ssl

How To Hard Code App.Config In dll file? C#

I am writing dll file for SAP B1, i need to embed App.Config in dll, no other option. Dll is using Web Service.
This is how my App.config looks like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WayBillsSoap">
<security mode="Transport" />
</binding>
<binding name="WayBillsSoap1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://services.rs.ge/WayBillService/WayBillService.asmx"
binding="basicHttpBinding" bindingConfiguration="WayBillsSoap"
contract="WayBillWS.WayBillsSoap" name="WayBillsSoap" />
</client>
</system.serviceModel>
</configuration>
You can't hard-code the App.config itself, because it simply isn't designed that way.
You can create your own config and embed it into your application using, for example, a resource file (.resx) or using constants to embed strings in a custom class.
But there is no way to embed the dll.
.NET does allow assemblies such as dlls to have their own yourdll.dll.config file. But you can't embed it. It must sit alongside you dll, just as it does for executables.
======= Edit after you posted your config =======
Ah. So here's the question. If you embed your config, that means by definition it can't change. So since you're okay with your config not changing -- since you want to embed it -- and it looks like you're using WCF, I would suggest you look at programmatically creating your WCF endpoint.
In WCF you can configure your endpoint in code instead of using an App.Config. That way you don't need a config at all.
Unfortunately, teaching your how to do this is beyond the scope of this question, but take a look at this answer: Programatically adding an endpoint. And try this google search: "wcf endpoint programmatically". That should help show you how to programmatically create a WCF endpoint.
I'm unsure about completely replacing the App.config but you can add and modify things found in it from code using the System.Configuration I've specifically used the System.Configuration.ConfigurationManager.AppSettings["SomeKey"]
Edit:
Doing that doesn't rewrite the App.config it simply temporarily adds/changes it

Relative path to WCF service from MVC web config path

So the story is that I need multiple test sites on a single IIS.
My application consists of a MVC project with a web.config file pointing towards the WCF Service located on the same server.
I have this folder structure on the IIS:
Developer1
-MVC
-WCF
Developer2
-MVC
-WCF
I have configured IIS so the devs can access
http://MyServer/Developer1/MVC
or
http://MyServer/Developer2/MVC
I have tried setting this path in the web.config file to contact the correct WCF "~/WCF/SomeService.svc" and "../WCF/SomeService.svc" but I can't get it to work and I can't find the correct syntax.
Why do you want to use a relative path? You could register both endpoints and use the one you need:
<endpoint name="dev1" address="http://MyServer/Developer1/MVC/WCF/SomeService.svc" binding="basicHttpBinding" contract="SomeServiceContract" />
<endpoint name="dev2" address="http://MyServer/Developer1/MVC/WCF/SomeService.svc" binding="basicHttpBinding" contract="SomeServiceContract" />
var svcProxy = new SomeServiceProxy("dev1");

What is running my WCF Service?

I'm getting an error when I try to run my WCF Service on IIS instead of ASP.NET Development Server.
Clarification: I don't get an error when I run the WCF Service when using a Windows Service or ASP.NET Development Server. ONLY IIS is the problem.
I'm using a console app to test the service. I've never had problems with the service until i tried using the IIS port.
Here is my app.config file of the console app. The top address and port number is the ASP.NET Dev Server port. The second one is the IIS port.
The following is my App.config file. The top one IIS port. The active one is the ASP.NET Development Server port. When I run the ASP.NET port, I get no errors. When I run the IIS port, I get an error. (Also I have about 4 ASP.NET ports appearing on my Taskbar. I don't know why.)
My App.config file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IWebService" />
</wsHttpBinding>
</bindings>
<client>
<!-- <endpoint address="http://localhost:9876/Service.svc" binding="wsHttpBinding"-->
<endpoint address="http://localhost:5182/Service.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IWebService"
contract="MyWCF_ServiceReference.IWebService"
name="WSHttpBinding_IWebService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
Here are some images.
This is the error message that I'm getting.
Is there a reason why the address below is different from the previous ones?
http:// localhost:8732 /Design_Time_Addresses/WCFServiceLibrary/WebService/mex
This is where it is crashing for some unknown reason. Its worth noting that part of the service works. Its only when it get to ValidPerson that it crashes.
(This also doesn't happen when using the ASP.NET Development Server port 5182. Only when using IIS port 9876)
This shows that at the WCF Service itself, the ValidPerson is actually working.
Here is the conf file its running on.
I hope you guys can help me. It must be something simple.
Ok, i wasn't asking the right question although i was learning as I went.
I need to make sure the address in the config file matched either the ASP.NET development server's address (which is mostly likely the default) or change it to the IIS address which would require me to check where the WSDL was being hosted adn use that address instead of the default one. Or use the addrress assigned to my Windows Service which i could find by opening up the project file and seeing which number and address was assigned to it.
The real problem was that my Application Pool account in SQL Server needed to be set to a role of db_owner. Then all my problems went away (once i got it on the right ports with the right addresses.)

Creating and Consuming a Webservice entirely within a DLL

Hope someone here can help me solve this !
I'm writing a custom plugin for Microsoft CRM, which on the creation or update of certain entities, carries out some tasks in the background on our Sharepoint instance, which can't be completed via CRM workflows as they don't have the functionality.
The problem is, that when creating the Service Reference, the defintion for the webservice, with the endpoint address, etc is stored in the DLL's .config file. When deploying the CRM Plugin, the .config file isn't available either when deploying it to disk, or to the database, and the plugin fails as soon as the I try to use the Webservice.
I've had a look at some documentation for BasicHttpBinding, but I'm not entirely sure how I would go about creating the Webservice programmatically, so that it is entirely contained within the DLL.
I'm not bothered about being able to amend the details without recompiling, as the code will be pretty much static anyway.
I've tried defining the Service Reference in the project, as "TestDws"
BasicHttpBinding SharepointWS = new BasicHttpBinding();
SharepointWS.Name = "SharepointWebservice";
EndpointAddress EndPoint = new EndpointAddress("http://hostname/_vti_bin/dws.asmx");
TestDws.DwsSoapClient temp = new TestDws.DwsSoapClient(SharepointWS, EndPoint);
However, the plugin just craps out at this point.
The original .config doesnt have much more in the way of configuration
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="DwsSoap" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://hostname/_vti_bin/dws.asmx"
binding="basicHttpBinding" bindingConfiguration="DwsSoap"
contract="TempDws.DwsSoap" name="DwsSoap" />
</client>
</system.serviceModel>
</configuration>
I recreated the Service Reference from scratch, and used the same BasicHttpBinding method as above and it worked second time round... albeit now with a HTTP401 on the Sharepoint Webservice !

Categories

Resources