Is it possible to take asp.net web adress from IIS - c#

I want to read web services information especially adress from iis.
For IIS7 I can read following information with this code.
var iisManager = new ServerManager();
sites = iisManager.Sites;
foreach (var site in sites)
{
IISService serv = new IISService();
serv.Name = site.Name;
serv.State= site.State.ToString();
serv.PhysicalPath= site.Applications["/"].VirtualDirectories[0].PhysicalPath;
allServices.Add(serv);
}
For II6
DirectoryEntry IIsEntities = new DirectoryEntry(Path);
foreach (DirectoryEntry IIsEntity in IIsEntities.Children)
{
if (IIsEntity.SchemaClassName == "IIsWebServer")
{
yield return new Website
(
IIsEntity.Properties["ServerComment"].Value.ToString(),
GetPath(IIsEntity),
(ServerState)IIsEntity.Properties["ServerState"].Value
);
}
}
I can read above information but I want to read end point information of asmx web service.
Thats like :
http://localhost:8091/Service1.asmx
Is it possible read port number or name of asmx file ?

Nope. IIS has nothing to do with it. IIS only concerns about hosting-related operations and serving requests. If you are talking about services, you might want to look at making your services discoverable, exposing metadata and WSDL. However, this will not expose any file or any "internals" of the service...just the interface (public facing details)...for example if you have a RESTful service, the physical files behind it will not be exposed.

I ask IIS for local adresses so I can succeded to get enough information to form asmx local web adress.
foreach (var site in sites)
{
IISService serv = new IISService();
serv.Name = site.Name;
serv.State= site.State.ToString();
serv.PhysicalPath= site.Applications["/"].VirtualDirectories[0].PhysicalPath;
System.Net.IPEndPoint endP = site.Bindings[0].EndPoint;
string protocol = site.Bindings[0].Protocol;
allServices.Add(serv);
}
I can get Binding information with this solution(port and Protocol). I
can find Service1.asmx file when I ask for *.asmx with Directory.GetFiles in PhysicalPath. So I get needed information to construct web services adress.
//What I need http://localhost:8091/Service1.asmx
string adress = protocol + "://localhost:" + endP.Port + "/" + " *.asmx file from PhysicalPath";

Related

How to find the location of a web application root directory from within my application?

List of installed applications from Registry, are often, retrieved from here
Software\Microsoft\Windows\CurrentVersion\Uninstall
The location of the programs can be retrieved from the relavent subkey "InstallLocation". However, this seems to not apply to windows and web services.
Windows Services location can be retrieved from
SYSTEM\CurrentControlSet\Services
How can I find information about Web Services and their location from registry?
The Microsoft.Web.Administration.dll can be used to query IIS, you can do things like,
Get List of all websites
Get info about a specific Website
Get info about web applications in a website
Get info about the binding in an application
Create/Modify, etc a website
....
A simple usage example would be
private ServerManager serverManager
{
get
{
if (_serverManager == null)
_serverManager = new ServerManager();
return _serverManager;
}
set { _serverManager = value; }
}
and you can use the above variable to get a specific site name
var site = serverManager.Sites.First(x => x.Name.ToLower() == siteName.ToLower());
where you can get the site names from serverManager.Sites
You can also open application webconfigs and modify,query,etc
public static System.Configuration.Configuration GetConfigurationFrom(string appName, string hostName, string site)
{
return System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(#"/" + appName, site, null, hostName);
}

SOAP error when connecting to NetSuite web services: "Namespace prefix ' soapenv' not defined"

I am getting the following error when connecting to a NetSuite production account, through the Suitetalk API:
I don't have problems connecting to the Sandbox account for this client. I am connecting through a C# WCF project. I don't believe the problem is with the c# project, since this code is being used in Production with many other clients.
It seems to me like the SOAP message being returned is incorrectly formatted - there seems to be a line break before the 'soapenv' element in the SOAP message. I am getting this error when creating a "get" request against the API(using passport login). This error occurs on any API call though, I did try simply logging in through the API as well.
I have double checked the login details and account information for this client and everything seems in orders. Besides, if this information is incorrect, I should be getting authentication errors - not malformed SOAP messages.
Any help will be appreciated, thanks!
It turns out that I needed to use the webservices.na3.netsuite WSDL. I was under the impression that the regular "webservices.netsuite" WSDL would direct any requests to the correct server.
So when connecting to a NetSuite account through SuiteTalk, be sure to make use of the correct WSDL and specify the correct endpoint along with your login credentials. You can check which server your account is hosted on by looking at the URL when logged into your NetSuite account.
Update
I made use of the newest 'DataCenterAwareNetSuiteService' class to dynamically get the correct data center for the current account that I am trying to connect to:
class DataCenterAwareNetSuiteService : NetSuiteService
{
private System.Uri OriginalUri;
public DataCenterAwareNetSuiteService(string account, bool doNotSetUrl)
: base()
{
OriginalUri = new System.Uri(this.Url);
if (account == null || account.Length == 0)
account = "empty";
if (!doNotSetUrl)
{
//var temp = getDataCenterUrls(account);
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + OriginalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}
public void SetAccount(string account)
{
if (account == null || account.Length == 0)
account = "empty";
this.Url = OriginalUri.AbsoluteUri;
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + OriginalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}
The above is called like so:
new DataCenterAwareNetSuiteService("*account number*", false);
With the latest version of NetSuite, some changes have been made to URLs. For instance, now you can have more than one SandBox URL. Because of this, the URL format has changed. The account number used when authenticating is also now different. For sandboxes the account Id is now passed up as ACCOUNTNUMBER_SANDBOXID, for example 12345678_SB1.
You can determine the URLs for the SOAP and REST services by using the datacenterurls endpoint and supplying the account # you would like to determine the URLS for.
https://rest.netsuite.com/rest/datacenterurls?account=YOUR_ACCOUNT_NUMBER
The functionality below is based on the answer from #Charl above.
I have made a couple changes below that provides the same functionality without using inheritance.
This may be a simpler implementation for a newer programmer who does not know how to use an inherited class.
var accountId = "1234567"; // Insert your account ID here
var Service = new NetSuiteService();
Service.Url = new Uri(Service.getDataCenterUrls(accountId).dataCenterUrls.webservicesDomain + new Uri(Service.Url).PathAndQuery).ToString();

Programmatically implement WCF with Certificate

I am quite new to WCF and trying to get my head around the security. I am still reading and learning, but I came to a point where I got a working version of WCF with Certificate authentication. I know that the code has some weaknesses; however, my initial goal was to create communication using certificate authentication. Also, I wanted to create everything programmatically (no Web.config configurations for the services or clients). The reason for this is that the client should be able to link an Assembly (Class Library) and get access to the server. Also, I am loading the certificates from the file system (again, I know this is not secure). I would like to get a little bit feedback.
The following client snippet is creating an object that I can use to connect to the server. The anonymous type T is my service interface e.g. IService.
Here is my client implementation:
var url = "URL TO WS";
var binding = new WSHttpBinding
{
Security =
{
Mode = SecurityMode.Message,
Message = {ClientCredentialType = MessageCredentialType.Certificate}
}
};
var endpoint = new EndpointAddress(url);
var channelFactory = new ChannelFactory<T>(binding, endpoint);
if (channelFactory.Credentials != null)
{
channelFactory.Credentials.ClientCertificate.Certificate =
new X509Certificate2(#"PATH\TO\Client.pfx"); // Client Certificate PRIVATE & PUBLIC Key
channelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None; // I know this is not good, but I dont have a valid certificate from a trusted entity
}
wcfClient = channelFactory.CreateChannel();
return wcfClient;
The service is a bit more complex. I use .svc files with their code-behind. If I understand the use of .svc files correctly, then I believe this is the entry point where the .NET framework creates a ServiceHost and automatically opens it? In my implementation I do not open the ServiceHost, I only implemented a ServiceHostFactoryBase and referenced it in the .svc Markup language. Look at the Factory section - this is the part where I implement my custom Host Factory.
<%# ServiceHost Language="C#" Debug="true"
Service="Service.Services.LevelService" CodeBehind="LevelService.svc.cs"
Factory="Service.Security.ServiceHostFactory.HostFactory" %>
And my custom Host Factory looks like this:
public class HostFactory : ServiceHostFactoryBase
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
var serviceType = Type.GetType(constructorString);
if (serviceType.GetInterfaces().Count() != 1)
throw new NotImplementedException("The service can only have one implemented interface");
var interfaceType = serviceType.GetInterfaces()[0];
var myServiceHost = new ServiceHost(serviceType, baseAddresses);
var httpBinding = new WSHttpBinding();
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
httpBinding.Security.Mode = SecurityMode.Message;
myServiceHost.Credentials.ServiceCertificate.Certificate = new X509Certificate2(#"PATH\TO\Server.pfx");
myServiceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
myServiceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new MyX509CertificateValidator();
myServiceHost.Credentials.ClientCertificate.Certificate = new X509Certificate2(#"PATH\TO\Client.cer");
myServiceHost.AddServiceEndpoint(interfaceType, httpBinding, String.Empty);
return myServiceHost;
}
}
The custom validator doess't do much yet, but here it is as well:
public class MyX509CertificateValidator : X509CertificateValidator
{
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
// Check that the certificate issuer matches the configured issuer.
//throw new SecurityTokenValidationException("Certificate was not issued by a trusted issuer");
}
}
If I understand correctly, the Server has ONLY the PUBLIC key of the client registered since I only reference the .cer file.
My big question is now, if I would like to get anything like this on a production server - and lets assume nobody will actually get the executables (including the certificates), would this be a possible solution to keep unwanted people out of my webservice? Basically, I don't want anybody else consuming my webservice - only if you have the proper certificate. Also, how much of an issue is the part where I set on the client:
CertificateValidationMode = X509CertificateValidationMode.None
I know there are many questions - but overall, I would like to know if I made some fundamental mistakes in this implementation.
Ok,
after going through a lot of tutorials and demo applications, I figured out that the best way to go ahead is actually using the Certificate Store on Windows. However, I still might consider a hybrid solution where the Server has the certificates in the Certificate store and the client has it embedded in a resource. If you are struggling with WCF and Certificates, have a look at those links:
IIS7 Permissions Overview - ApplicationPoolIdentity
I was able to create Transport as well as Message secured WCF web services. I would suggest to READ the linked articles because there is so much information that will make you understand certificates and their usage. Especially when dealing with self-singed certificates!
I ended up implementing wsHttpBinding using Message Security Mode + Client Certificate with ChainTrust.
Hope this will help someone else!

Programmatically retrieve the site URL from inside an Azure website

Azure websites have a default "site URL" provided by Azure, something like mysite.azurewebsites.net. Is it possible to get this URL from inside the website itself (i.e. from the ASP.NET application)?
There are several properties in the Environment and HttpRuntime class that contain the name of the website (e.g. "mysite") so that is easily accessible. Things are getting complicated when not the default but e.g. the staging slot of the site is accessed (that has the site URL like mysite-staging.azurewebsites.net).
So I was just wondering whether there is a straightforward way of getting this site URL directly. If not, then using one of the mentioned classes to get the site name and then somehow detecting the site slot (that could e.g. be set through a configuration value from the Azure portal) would be the solution
Edit (2/4/16): You can get the URL from the appSetting/EnvironmentVariable websiteUrl. This will also give you the custom hostname if you have one setup.
There are few of ways you can do that.
1. From the HOSTNAME header
This is valid only if the request is hitting the site using <SiteName>.azurewebsites.net. Then you can just look at the HOSTNAME header for the <SiteName>.azurewebsites.net
var hostName = Request.Headers["HOSTNAME"].ToString()
2. From the WEBSITE_SITE_NAME Environment Variable
This just gives you the <SiteName> part so you will have to append the .azurewebsites.net part
var hostName = string.Format("http://{0}.azurewebsites.net", Environment.ExpandEnvironmentVariables("%WEBSITE_SITE_NAME%"));
3. From bindingInformation in applicationHost.config using MWA
you can use the code here to read the IIS config file applicationHost.config
and then read the bindingInformation property on your site. Your function might look a bit different, something like this
private static string GetBindings()
{
// Get the Site name
string siteName = System.Web.Hosting.HostingEnvironment.SiteName;
// Get the sites section from the AppPool.config
Microsoft.Web.Administration.ConfigurationSection sitesSection =
Microsoft.Web.Administration.WebConfigurationManager.GetSection(null, null,
"system.applicationHost/sites");
foreach (Microsoft.Web.Administration.ConfigurationElement site in sitesSection.GetCollection())
{
// Find the right Site
if (String.Equals((string) site["name"], siteName, StringComparison.OrdinalIgnoreCase))
{
// For each binding see if they are http based and return the port and protocol
foreach (Microsoft.Web.Administration.ConfigurationElement binding in site.GetCollection("bindings")
)
{
var bindingInfo = (string) binding["bindingInformation"];
if (bindingInfo.IndexOf(".azurewebsites.net", StringComparison.InvariantCultureIgnoreCase) > -1)
{
return bindingInfo.Split(':')[2];
}
}
}
}
return null;
}
Personally, I would use number 2
Also, you can use Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME").
This will return full URL ("http://{your-site-name}.azurewebsites.net"), no string manipulations required.
To see a full list of properties available in environment variables just type Get-ChildItem Env: in SCM PowerShell debug console.

Communication between a Client -> WCF Service -> ASP.NET Webpage

i try to build a Client which sends data to a WCF Service. There is an ASP.NET Webpage which should recieve those information and put them in textfields etc.
Here is the method in my client:
OutlookPluginService.BookingRequest breq = new OutlookClient.OutlookPluginService.BookingRequest();
breq.subject = "This is my subject";
breq.numParticipants = 6;
client.getBookingURL("1234", breq);
This method sends the data to the WCF Webservice and recieves the ASP.NET URL.
This is my WCF Method:
public string getBookingURL(string guid, BookingRequest request,string token,string exitURL)
{
BookingRequest breq = new BookingRequest();
HttpContext current = HttpContext.Current;
string baseUrl = current.Request.Url.Scheme + "://"
+ current.Request.Url.Authority
+ current.Request.ApplicationPath.TrimEnd('/') + '/'
+ "WebPage/Booking/BBooking.aspx";
return baseUrl;
}
i can access to the data from here but i dont know how to transfer the data to the asp.net Webpage.
is it possible to solve this problem with sessions?
thanks in advance for your help/ideas
you have two options;
1) you may use pooling, which makes calls to the related service in predetermined time intervals to fetch the newly added data.
or
2) you may use a pull - push structure which enables you to push data from your WCF service to your ASP.NET application. Refer to How do I implement a Push-Pull web application in C# asp.net

Categories