Sending a Request Message through WCF stack - c#

We have a WCF Service (ServiceContact + Implementation class). The service was originally self hosted using ServiceHost and BasicHttpBinding using TransportWithMessageCredential.
Clients have been configured to use this service and cannot be changed except to be pointed to a new url.
Now we want to change how the service is hosted. The entry point on the new host (not IIS) is an Http request message (headers and body). The idea is that we point clients to the new host and bridge the gap between the Http request and the WCF Stack.
In theory it sounds like we have to create a new TransportBindingElement, followed by a CustomBinding to use this transport. This is proving mind bogglingly complicated.
Alternatively, what sounds easier is, if possible, to create a WCF Message instance from the http request, and somehow send it through the various existing binding elements used by BasicHttpBinding (mainly so all the Security headers are processed), and somehow end up in our WCF Service implementation.
Does anyone have any idea on if and how this may be possible?
2019-06-14: Adding sample to demonstrate challenge:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ConsoleApp5
{
[ServiceContract]
public interface IService
{
[OperationContract]
string Invert(string s);
}
public interface IServiceChannel : IService, IClientChannel
{
}
public class Service : IService
{
public string Invert(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
}
class Program
{
static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
Console.WriteLine("Enter 1 for WCF Listene, anything else for HttpListener");
var option = Console.ReadLine();
if(option == "1")
{
Task.Run(() => StartWCFHost());
}
else
{
Task.Run(() => StartHttpListenerHost());
}
Console.WriteLine("hosting");
Console.WriteLine("Enter string to invert");
var streingToInvert = Console.ReadLine();
var binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
var cf = new ChannelFactory<IService>(binding, new EndpointAddress("https://localhost:20443/myservice"));
cf.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "dc72486676c5e983589897fca5051a360376777d");
var client = cf.CreateChannel();
try
{
var r = client.Invert(streingToInvert);
Console.WriteLine(r);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
private static void StartHttpListenerHost()
{
var web = new HttpListener();
web.Prefixes.Add("https://localhost:20443/");
Console.WriteLine("Listening..");
web.Start();
while(true)
{
var context = web.GetContext();
var soapMessage = Message.CreateMessage(XmlReader.Create(context.Request.InputStream), int.MaxValue, MessageVersion.Soap11);
//TODO: How do we process request security related headers and give a proper response to client?
//Ideally we want to use Service implementation class and WCF Bindings/BindingElements to process headers and generate response message
//For the time being just read body write it to console
var body = soapMessage.GetReaderAtBodyContents().ReadOuterXml();
Console.WriteLine(soapMessage.ToString());
Console.WriteLine(body);
context.Response.Close();
}
}
private static void StartWCFHost()
{
ServiceHost sh = new ServiceHost(typeof(Service), new Uri("https://localhost:20443/myservice"));
var binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
var se = sh.AddServiceEndpoint(typeof(IService), binding, "https://localhost:20443/myservice");
sh.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpsGetEnabled = true });
sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "dc72486676c5e983589897fca5051a360376777d");
sh.Credentials.ClientCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
sh.Open();
}
}
}

Related

How to authorize Google anlaytics data api with OAuth2

I am trying to connect to the new Google Analytics Data api using C# to request data from the new google analytics GA4. The only sample i can find is
Quickstart client libraries .net This does work but it uses a service account. The cloud .net client library google-cloud-dotnet only has examples for using a service account.
When i try to pass it desktop app credentials for using Oauth" authorization i get
Error creating credential from JSON. Unrecognized credential type.
using System;
using System.Threading;
using System.Threading.Tasks;
using Google.Analytics.Data.V1Beta;
namespace GoogleAnalyticsExamplesData
{
class Program
{
private const string PropertyId = "250796939";
private const string PathToCreds = #"C:\dev\ServiceAccountCred.json";
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
// Check whether the environment variable exists.
var environmentVariable = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
// If necessary, create it.
if (environmentVariable == null)
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", PathToCreds);
await SampleRunReport(PropertyId);
}
static async Task SampleRunReport(string propertyId = "YOUR-GA4-PROPERTY-ID")
{
// Using a default constructor instructs the client to use the credentials
// specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
var client = await BetaAnalyticsDataClient.CreateAsync(CancellationToken.None);
var request = new RunReportRequest
{
Property = "properties/" + PropertyId,
Dimensions = {new Dimension {Name = "date"},},
Metrics = {new Metric {Name = "totalUsers"}, new Metric {Name = "newUsers"}},
DateRanges = {new DateRange {StartDate = "2021-04-01", EndDate = "today"},},
};
var response = await client.RunReportAsync(request);
Console.WriteLine("Report result:");
foreach (var row in response.Rows)
{
Console.WriteLine(
$"{row.DimensionValues[0].Value}, {row.MetricValues[0].Value}, {row.MetricValues[1].Value}");
}
}
}
}
Links to Google.Analytics.Data.V1Beta Web client credentials, desktop credentials
After several hours of digging around i found that you can use ICredential using a builder. This works with a Desktop app credentials, for installed applications.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Google.Analytics.Data.V1Beta;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Util.Store;
namespace GoogleAnalyticsExamplesData
{
class Program
{
private const string PropertyId = "250796939";
private const string PathToCreds = #"C:\dev\credentials.json";
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
await SampleRunReport(PropertyId);
}
static async Task SampleRunReport(string propertyId = "YOUR-GA4-PROPERTY-ID")
{
// Using a default constructor instructs the client to use the credentials
// specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
//var client = await BetaAnalyticsDataClient.CreateAsync(CancellationToken.None);
BetaAnalyticsDataClient client ;
await using (var stream = new FileStream(PathToCreds, FileMode.Open, FileAccess.Read))
{
// Requesting Authentication or loading previously stored authentication for userName
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
new[] { "https://www.googleapis.com/auth/analytics.readonly"},
"userName",
CancellationToken.None,
new FileDataStore("credPath", true)).Result;
client = await new BetaAnalyticsDataClientBuilder
{
TokenAccessMethod = credential.GetAccessTokenForRequestAsync
}.BuildAsync();
}
var request = new RunReportRequest
{
Property = "properties/" + PropertyId,
Dimensions = {new Dimension {Name = "date"},},
Metrics = {new Metric {Name = "totalUsers"}, new Metric {Name = "newUsers"}},
DateRanges = {new DateRange {StartDate = "2021-04-01", EndDate = "today"},},
};
var response = await client.RunReportAsync(request);
Console.WriteLine("Report result:");
foreach (var row in response.Rows)
{
Console.WriteLine(
$"{row.DimensionValues[0].Value}, {row.MetricValues[0].Value}, {row.MetricValues[1].Value}");
}
}
}
}

How to inject dependency on WCF service used as RESTFul service on selfhost enviroment

I need some example of how to implement a RESTfull service with WCF tecnology on a self-host environment and by using a DI container (possibly SimpleInjector).
On https://simpleinjector.readthedocs.io/en/latest/wcfintegration.html i have found how to integrate a custom factory but it's made for ServiceHost but this it's not suitable for a RESTFull service that instead use WebServiceHost?
I tried to configure service host to be compatible with webHttpBinding but nothing happened and i receive this kind of error:
<Fault
xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
<Code>
<Value>Sender</Value>
<Subcode>
<Value
xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:DestinationUnreachable
</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="it-IT">Impossibile elaborare nel destinatario il messaggio con To 'http://localhost:8733/3AdispPushBatchService/pushpost' a causa di una mancata corrispondenza AddressFilter in EndpointDispatcher. Controllare la corrispondenza di EndpointAddresses del mittente e del destinatario.</Text>
</Reason>
</Fault>
There is another integration package to use for WebServiceHost?
This is the example that i have made
AAADispPushBatchService.cs
using System;
using System.Configuration;
using System.IO;
using System.ServiceModel.Activation;
using System.Text;
using Newtonsoft.Json;
namespace AAARestService
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class AAADispPushBatchService : IAaaDispPushBatchService
{
public string GetBatchJson(Stream jsonFileContent)
{
try
{
var sr = new StreamReader(jsonFileContent, Encoding.UTF8);
var str = sr.ReadToEnd();
if (String.IsNullOrWhiteSpace(str))
throw new ArgumentException("No data inside body request");
var definition = new { BatchName = "" };
var json = JsonConvert.DeserializeAnonymousType(str, definition);
if (json == null)
throw new ArgumentException("No valid json inside");
if (String.IsNullOrWhiteSpace(json.BatchName))
throw new ArgumentException("BatchName not present");
var currentDir = ConfigurationManager.AppSettings["BatchPath"];
Directory.CreateDirectory(currentDir);
var filepath = Path.Combine(currentDir, json.BatchName+".json");
File.WriteAllText(filepath, str);
return $"Saved in {filepath}";
}
catch (Exception e)
{
return e.Message;
}
}
}
}
IAaaDispPushBatchService.cs
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace AAARestService
{
[ServiceContract(Name = "AAADispPushBatchService")]
public interface IAaaDispPushBatchService
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "pushpost", BodyStyle = WebMessageBodyStyle.Bare,ResponseFormat = WebMessageFormat.Json)]
string GetBatchJson(Stream jsonFileContent);
}
}
EDIT!!!!!
BTW I try to add simpleinjector here are the example based on what i found in the blog
Bootstrapper.cs
using System.Reflection;
using SimpleInjector;
namespace AAARestService
{
public static class BootStrapper
{
public static readonly Container Container;
static BootStrapper()
{
Container container = new Container();
container.Register<IMyDateTimeService,MyDAteTimeService>();
container.RegisterWcfServices(Assembly.GetExecutingAssembly());
Container = container;
}
}
}
MyWebServiceHostFactory.cs
public class MyWebServiceHostFactory : SimpleInjectorServiceHostFactory
{
public ServiceHost GetWebServiceEndpoint(Type serviceType,Uri baseAddress)
{
Uri[] addresses=new Uri[]{baseAddress};
var service = CreateServiceHost(serviceType, addresses);
ServiceEndpoint sep = service.AddServiceEndpoint(typeof(IAaaDispPushBatchService), new WebHttpBinding(), baseAddress);
sep.EndpointBehaviors.Add(new WebHttpBehavior());
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
service.Description.Behaviors.Add(smb);
return service;
}
protected override ServiceHost CreateServiceHost(Type serviceType,
Uri[] baseAddresses)
{
var host = new SimpleInjectorServiceHost(
BootStrapper.Container,
serviceType,
baseAddresses);
return host;
}
}
Main
static void Main(string[] args)
{
try
{
Uri httpUrl = new Uri("http://localhost:8733/3AdispPushBatchService");
Uri httpUrl1 = new Uri("http://localhost:8734/3AdispPushBatchService");
//ServiceHost selfhost = new ServiceHost(typeof(AAADispPushBatchService), httpUrl);
//ServiceEndpoint sep =selfhost.AddServiceEndpoint(typeof(IAaaDispPushBatchService),new WebHttpBinding(), httpUrl);
//sep.EndpointBehaviors.Add(new WebHttpBehavior());
//ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
//smb.HttpGetEnabled = true;
//selfhost.Description.Behaviors.Add(smb);
MyWebServiceHostFactory factory = new MyWebServiceHostFactory();
var selfhost=factory.GetWebServiceEndpoint(typeof(AAADispPushBatchService), httpUrl);
selfhost.Open();
//WebServiceHost webHost = new WebServiceHost(typeof(AAADispPushBatchService),httpUrl1);
//webHost.Open();
foreach (ServiceEndpoint se in selfhost.Description.Endpoints)
Console.WriteLine("Service is host with endpoint " + se.Address);
//foreach (ServiceEndpoint se in webHost.Description.Endpoints)
// Console.WriteLine("Service is host with endpoint " + se.Address);
//Console.WriteLine("ASP.Net : " + ServiceHostingEnvironment.AspNetCompatibilityEnabled);
Console.WriteLine("Host is running... Press <Enter> key to stop");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
I haven't tried integration with WCF using dependency injection technology, maybe the solution in that blog is worth a try. I also don't recommend you use dependency injection in WCF, because it does not support dependency injection natively. In addition, for servicehost hosting WCF REST-style services, we need to add WebHttp behavior on the service endpoint. Please refer to the following code implementation.
Uri uri = new Uri("http://localhost:8004");
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.None;
using (ServiceHost sh = new ServiceHost(typeof(MyService), uri))
{
ServiceEndpoint se=sh.AddServiceEndpoint(typeof(IService), binding,"");
se.EndpointBehaviors.Add(new WebHttpBehavior());
sh.Opened += delegate
{
Console.WriteLine("Service is ready");
};
sh.Closed += delegate
{
Console.WriteLine("Service is clsoed");
};
sh.Open();
Console.ReadLine();
//pause
sh.Close();
Console.ReadLine();
Feel free to let me know if there is anything I can help with.

Azure Function Runs Locally But Not On Azure

My function is running locally but when I publish it to Azure it is erroring.
The error is
Value cannot be null. Parameter name: format
Googling this seems to suggest the input to the function is wrong but I am posting the exact same JSON that allows it to run locally.
I am lost to how I fix this. Any ideas?
Code below
using System;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;
namespace MyFunction
{
public static class Login
{
[FunctionName("Login")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, ILogger log)
{
Boolean websiteEnabled = false;
Guid contactId = new Guid();
log.LogInformation("C# HTTP trigger function processed a request.");
dynamic data = await req.Content.ReadAsAsync<object>();
string username = data?.username;
string password = data?.password;
string passwordHash = "";
User user = new User();
OrganizationServiceProxy _serviceProxy;
IOrganizationService _service;
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.UserName.UserName = ConfigurationManager.AppSettings["OrganisationUsername"];
clientCredentials.UserName.Password = ConfigurationManager.AppSettings["OrganisationPassword"];
Uri organisationUri = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
Uri realm = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
using (_serviceProxy = new OrganizationServiceProxy(organisationUri, realm, clientCredentials, null))
{
_serviceProxy.EnableProxyTypes();
_service = (IOrganizationService)_serviceProxy;
QueryByAttribute querybyattribute = new QueryByAttribute("contact");
querybyattribute.ColumnSet = new ColumnSet("cbob_websitepassword","cbob_websiteenabled","contactid","fullname", "parentcustomerid");
querybyattribute.Attributes.AddRange("emailaddress1");
querybyattribute.Values.AddRange(username);
EntityCollection retrieved = _service.RetrieveMultiple(querybyattribute);
if(retrieved.Entities.Count == 1)
{
passwordHash = retrieved.Entities[0].GetAttributeValue<String>("cbob_websitepassword");
websiteEnabled = retrieved.Entities[0].GetAttributeValue<Boolean>("cbob_websiteenabled");
contactId = retrieved.Entities[0].GetAttributeValue<Guid>("contactid");
user.Account = retrieved.Entities[0].GetAttributeValue<EntityReference>("parentcustomerid").Name.ToString();
user.Email = username;
user.LoggedInUser = retrieved.Entities[0].GetAttributeValue<String>("fullname");
user.AccountID = retrieved.Entities[0].GetAttributeValue<EntityReference>("parentcustomerid").Id.ToString();
user.BookingID = retrieved.Entities[0].Id.ToString();
} else
{
return req.CreateResponse(HttpStatusCode.BadRequest, "Not allowed");
}
}
Boolean hash = bCryptHash(passwordHash, contactId.ToString() + "-" + password);
Console.WriteLine(hash);
if (!websiteEnabled)
{
return req.CreateResponse(HttpStatusCode.BadRequest, "Not allowed");
}
if (hash)
{
string output = JsonConvert.SerializeObject(user).ToString();
return req.CreateResponse(HttpStatusCode.OK, output);
} else
{
return req.CreateResponse(HttpStatusCode.BadRequest, "Not allowed");
}
}
public static Boolean bCryptHash(string hash, string submitted)
{
Boolean hashPassword = BCrypt.Net.BCrypt.Verify(submitted,hash);
return hashPassword;
}
public static String sha256_hash(string value)
{
StringBuilder Sb = new StringBuilder();
using (var hash = SHA256.Create())
{
Encoding enc = Encoding.UTF8;
Byte[] result = hash.ComputeHash(enc.GetBytes(value));
foreach (Byte b in result)
Sb.Append(b.ToString("x2"));
}
return Sb.ToString();
}
}
}
Uri organisationUri = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
Uri realm = new Uri(String.Format(ConfigurationManager.AppSettings["OrganisationURL"]));
My guess is that one or both of those lines may be the problem. You are using String.Format here where the first parameter is the format parameter. The AppSettings you are providing for that parameter seem to be unavailable. Make sure you have those configuration values available when you deploy your function.
Additionally: If you don't provide any objects to the String.Format that get inserted in the String, why are you using it at all?
Make sure you have added those local app settings (i.e OrganisationUsername and so on in local.settings.json file) to Application settings. Find it in Azure portal, Platform features> Application settings. When we publish Function project to Azure, it's by design that content in local.settings.json is not published because it's designed for local dev.
When we publish Functions with VS, there's a friendly dialog to update Application settings.

Consuming wsdl url by passing method name and parameters and getting response without adding web reference?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//Added for samplecode
using System.CodeDom.Compiler;
using System.Security.Permissions;
using System.Web.Services.Description;
using System.Reflection;
using System.CodeDom;
using System.Diagnostics;
namespace DynamicSoap
{
public static class DynamicWebService
{
public static Object CallWebService(string webServiceAsmxUrl, string serviceName, string methodName, object[] args)
{
try
{
System.Net.WebClient client = new System.Net.WebClient();
//-Connect To the web service
System.IO.Stream stream = client.OpenRead(webServiceAsmxUrl + "?wsdl");
//Read the WSDL file describing a service.
ServiceDescription description = ServiceDescription.Read(stream);
//Load the DOM
//--Initialize a service description importer.
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
importer.ProtocolName = "Soap12"; //Use SOAP 1.2.
importer.AddServiceDescription(description, null, null);
//--Generate a proxy client.
importer.Style = ServiceDescriptionImportStyle.Client;
//--Generate properties to represent primitive values.
importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
//Initialize a Code-DOM tree into which we will import the service.
CodeNamespace codenamespace = new CodeNamespace();
CodeCompileUnit codeunit = new CodeCompileUnit();
codeunit.Namespaces.Add(codenamespace);
//Import the service into the Code-DOM tree.
//This creates proxy code that uses the service.
ServiceDescriptionImportWarnings warning = importer.Import(codenamespace, codeunit);
if (warning == 0)
{
//--Generate the proxy code
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
//--Compile the assembly proxy with the
// appropriate references
string[] assemblyReferences = new string[] {
"System.dll",
"System.Web.Services.dll",
"System.Web.dll",
"System.Xml.dll",
"System.Data.dll"
};
//--Add parameters
CompilerParameters parms = new CompilerParameters(assemblyReferences);
parms.GenerateInMemory = true; //(Thanks for this line nikolas)
CompilerResults results = provider.CompileAssemblyFromDom(parms, codeunit);
//--Check For Errors
if (results.Errors.Count > 0)
{
foreach (CompilerError oops in results.Errors)
{
System.Diagnostics.Debug.WriteLine("========Compiler error============");
System.Diagnostics.Debug.WriteLine(oops.ErrorText);
}
throw new Exception("Compile Error Occured calling WebService.");
}
//--Finally, Invoke the web service method
Object wsvcClass = results.CompiledAssembly.CreateInstance(serviceName);
MethodInfo mi = wsvcClass.GetType().GetMethod(methodName);
return mi.Invoke(wsvcClass, args);
}
else
{
return null;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}
In the above code while importing:
ServiceDescriptionImportWarnings warning = importer.Import(codenamespace, codeunit);
warning should come 0 then only it would go inside the if statement. But I'm getting CodeNotGenerated
I'm not able to figure out what the problem is. Can anyone please explain?

Inputting values to a string as a website URL for the page to be downloaded

I'm messing around with the System.Net library in C# and I'm trying to simply have it set up such that you enter an url and it will take that as a string and put that into the parameter for the URl in the Client.DownloadString() field.
Here is my code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
namespace StringDownloadTest
{
class GetInformation
{
string EnterString;
public string InputString()
{
EnterString = Console.ReadLine();
return EnterString;
}
}
class DownloadString
{
static void Main(string[] args)
{
GetInformation R = new GetInformation();
R.InputString();
string downloadedString;
System.Net.WebClient client;
client = new System.Net.WebClient();
downloadedString = client.DownloadString(R.InputString());
Console.WriteLine("String: {0}", downloadedString);
}
}
}
Any help here, it will compile but the program crashes.
You're calling R.InputString twice and only entering input for the first time.
Try:
GetInformation R = new GetInformation();
Console.WriteLine("Please enter a valid url protocol://domain");
var input = R.InputString();
Uri uri;
if(!Uri.TryCreate(input, UriKind.Absolute, out uri))
{
Console.WriteLine("Url format could not be determined for {0}", input);
Environment.Exit(1);
}
var client = new System.Net.WebClient();
var downloadedString = client.DownloadString(uri);
Console.WriteLine("String: {0}", downloadedString);

Categories