Configuring WCF Services in Code WCF 4.5 - asp.net

Hi, I am trying to configure wcf using code behind, below is the code:
public static void Configure(ServiceConfiguration config)
{
string configPath = ConfigurationManager.AppSettings["wcfconfigDBPath"];
// Enable “Add Service Reference” support
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
// set up support for http, https, net.tcp, net.pipe
if (isEnabled(configPath, "enablehttp"))
config.EnableProtocol(new BasicHttpBinding());
if (isEnabled(configPath, "enablenettcp"))
config.EnableProtocol(new NetTcpBinding());
if (isEnabled(configPath, "enablepipe"))
config.EnableProtocol(new NetNamedPipeBinding());
}
private static bool isEnabled(string path, string elementName)
{
try
{
string elementValue = string.Empty;
bool returnVal = false;
using (XmlTextReader reader = new XmlTextReader(path))
{
reader.ReadToFollowing(elementName);
if (reader.Read())
elementValue = reader.Value;
}
if (!string.IsNullOrEmpty(elementValue))
{
bool.TryParse(elementValue, out returnVal);
}
return returnVal;
}
catch (Exception ex)
{
return false;
}
}
The above code is not working. I am not sure when the "static void Configure" gets fired.
My question is, is there any way to enable/disable the protocol based on DB/xml configuration without bringing down the service?

New feature in .NET 4.5 which probably can be used in your case:
Note: The configure method is called by WCF before the service host is opened.
The Configure method takes a ServiceConfiguration instance that enables the developer to add endpoints and behaviors. This method is called by WCF before the service host is opened. When defined, any service configuration settings specified in an app.config or web.config file will be ignored.
The following code snippet illustrates how to define the Configure method and add a service endpoint, an endpoint behavior and service behaviors:
public class Service1 : IService1
{
public static void Configure(ServiceConfiguration config)
{
ServiceEndpoint se = new ServiceEndpoint(new ContractDescription("IService1"), new BasicHttpBinding(), new EndpointAddress("basic"));
se.Behaviors.Add(new MyEndpointBehavior());
config.AddServiceEndpoint(se);
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Refer for complete example to:https://msdn.microsoft.com/en-us/library/hh205277(v=vs.110).aspx

Related

Best way to pass configuration to Topshelf.HostFactory.Run in .Net core

I'm trying to develop/convert current .Net framework code of Task Consumer to Top shelf and .NET core 3.1 . I want to read the config data from json file and use those in start as well as in consume methods.
What is the best and simplest way to pass config data to Task Consumer service and other end points
Any suggestion/comments are helpful.
Thanks in advance .
My current code is
static void Main(string[] args)
{
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", true,true).Build();
var test2 = configuration.GetSection("RabbitMQSettings");
Console.WriteLine(HostFactory.Run(cfg => cfg.Service<TaskConsumerService>()));
}
ConsumerService code
public class TaskConsumerService : ServiceControl
{
IBusControl _bus;
IConfiguration _configuration;
public bool Start(HostControl hostControl)
{
_bus = ConfigureBus();
_bus.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
_bus?.Stop(TimeSpan.FromSeconds(30));
return true;
}
IBusControl ConfigureBus()
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var rabbitMQUrl = ConfigurationManager.AppSettings["RabbitMQSettings:RabbitMQHostUrl"];
cfg.Host(new Uri(rabbitMQUrl) , h =>
{
h.Username(ConfigurationManager.AppSettings["RabbitMQSettings:username"]);
h.Password(ConfigurationManager.AppSettings["RabbitMQSettings:pwd"]);
});
var queue0 = ConfigurationManager.AppSettings["QueName"];
cfg.ReceiveEndpoint(queue0 , e =>
{
e.Consumer<TransformConsumer>();
});
});
}
}
Consumer code
public class TransformConsumer : IConsumer<IExecuteTransform>
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
string address = string.Empty;
const string json = "application/json";
public async Task Consume(ConsumeContext<IExecuteTransform> context)
{
m_log.Info(" Transform started.");
// Processing
try
{
address = string.Concat(ConfigurationManager.AppSettings["RabbitMQSettings:RabbitMQHost"] , ConfigurationManager.AppSettings["RabbitMQSettings:queName"]);
IExecuteTransform message = await ConsumeSendEndPoint(context , address);
m_log.Info(" Transform Process completed.");
}
catch ( Exception e )
{
m_log.Error("Transform failed");
throw e;
}
}
}
I'd recommend moving from Topshelf to the .NET Core Generic Host, which is used in the console service sample. It uses the standard .NET Core extension packages for configuration, dependency injection, etc.

Publish on .NET Core 2.2 SignalR Hub as EXE not working on Self-Host but works in Visual Studio

I have a Hub that works inside Visual Studio Community 2017 for ASP.Net Core & SignalR. Everything works beautifully as long as it runs under VS. I read what is available & am not getting any luck. I have a HostedService that on StartAsync kicks off a thread with the Background prop set to true. This thread reads from a socket & then calls SendMessage on the Hub. I'm not sure what I'm doing wrong. It publishes an exe, but it is not working.
I have read all that I can find. I added a Hosted Service that is added under Startup.
// STARTUP
public class cRioHubStartup {
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddMvc();
services.AddHostedService<cRioHubHostService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
string virtDir = cRioHubGlobals.getHubUrl().VirtualDirectory;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
//app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
//app.UseCors(CorsOptions.AllowAll);
app.UseSignalR(routes =>
{
routes.MapHub<cRioHub>(virtDir);
});
app.UseMvc();
app.Run(async (context) =>
{
await context.Response.WriteAsync("cRioHub Started!");
});
}
/*
var hubContext = provider.GetService<IHubContext<cRioHub>>();
services.AddSingleton(provider =>
{
var hubContext = provider.GetService<IHubContext<cRioHub>>();
var update = new Update(hubContext);
return update;
});
*/
}
// HUB HOSTED SERVICE which kicks off background thread
public class cRioHubHostService : IHostedService, IDisposable
{
private static Thread _t = null;
public Thread thread
{
get { return _t; }
}
// Summary: Triggered when the application host is ready to start the service.
public Task StartAsync(CancellationToken cancellationToken)
{
_t = LaunchHub();
return Task.CompletedTask;
}
// Summary: Triggered when the application host is performing a graceful shutdown.
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public void Dispose()
{
_t = null;
}
public static Thread LaunchHub()
{
Object orfu = new object(); // saved for fut. use if needed
// set up hub
cRioHubConnection hub = new cRioHubConnection(cRioHubGlobals.getHubUrl(), cRioHubGlobals.getHubUrl().Name);
cRioHubGlobals.setHubConnection(new cRioHubConnection(hub));
//Globals.HubCnxn.SendMessage("Take2!");
// call thread to start TCP client wh. writes back to the hub on cRio msg. arrival
Thread t = new Thread(cRioHubTcpClient.cRioRunClient);
t.IsBackground = true;
t.Start(orfu);
return t;
}
public static void cRioRunClient(Object orfu)
{
string consMsg = "";
string urlHub = cRioHubGlobals.getHubUrl().makeUrl();
string urlCRio = cRioHubGlobals.getCRioUrl().makeUrl();
string fmtHubUrl = "Hub URL={0}" ;
string fmtCRioUrl = "cRio URL={0}";
consMsg = String.Format(fmtHubUrl, urlHub);
Console.WriteLine(consMsg);
consMsg = String.Format(fmtCRioUrl, urlCRio);
Console.WriteLine(consMsg);
cRioHubGlobals.setCRioTcpClient(new cRioHubTcpClient(orfu)); // gets its connection info from cRioHubGlobals
cRioHubGlobals.getCRioTcpClient().Message += (s, a) => Console.WriteLine("Client: " + a.Message);
Task clientTask = cRioHubGlobals.getCRioTcpClient().RunAsync();
Console.WriteLine("Program: Hit any char to stop.");
ConsoleEx.ReadChar();
cRioHubGlobals.getCRioTcpClient().Stop = true;
cRioHubGlobals.getCRioTcpClient().Dispose();
clientTask = null;
}
public static Task cRioStopClient()
{
Task tskHub = null;
cRioHubTcpClient client = cRioHubGlobals.getCRioTcpClient();
if (client != null)
{
client.Stop = true;
client.Dispose();
tskHub = cRioHubGlobals.getHubConnection().Stop();
}
Console.WriteLine("Stopping service!");
return tskHub;
}
The problem is the publisher with the appsettings & launch. If you choose a port other than the default 5000, it is not working. If you choose 5000, it works. This appears to be a bug.

Kentor Auth Services choose programmaticaly entityId based on page url

I'm integrating our asp.net MVC application with SAML2 Authentication. And using Kentor.AuthServices as module as described at kentor.AuthServices Configuration
Everithing works fine. But next step is to add usage of second service provider (which configured to use another auth mechanisms on server side) only for specified range of pages.
First, how to configure it via web.config to add second SP (not the second IdP in scope of first SP) with different entityId.
And Second, how to switch programmatically to second SP? I assume that it should happend in global.asax file in method Application_BeginRequest, but how?
Using two different SP instances in the same application is a quite rare scenario. But if you are really sure you need it, it can be achieved.
You will have to use the Kentor.AuthServices.Owin package and do the configuration in code - web.config won't do. Register two instances of the middleware. Each one will have their own configuration, including their own SP EntityID. Also make sure to change the ModulePath of at least one of them so that they get different endpoint addresses.
To challenge an authentication from either one, set the right authentication scheme in the challenge (typically in a ChallengeResult returned from a controller)
Self-answering.
Here is a workaround for multiple SP for MVC or HttpModule package, switching is based on specified range of URLs. In my case different SP realize different amount of security factors.
First, implementing custom IOptions and CookieHandler, with ability to switch to correct instance. In the web.config file, two kentor.authServices sections must be defined. In my case only "entityId" attribute differs.
public class CustomOptions : IOptions
{
private IOptions options1Factor;
private IOptions options2Factor;
private Func<bool> _checkIsSecure;
public CustomOptions(Func<bool> checkIsSecure)
{
_checkIsSecure = checkIsSecure;
AddOption(out options2Factor, "kentor.authServices1");
AddOption(out options1Factor, "kentor.authServices");
}
private void AddOption(out IOptions options, string sectionName)
{
var sp = new SPOptions((KentorAuthServicesSection)ConfigurationManager.GetSection(sectionName));
options = new Options(sp);
KentorAuthServicesSection.Current.IdentityProviders.RegisterIdentityProviders(options);
KentorAuthServicesSection.Current.Federations.RegisterFederations(options);
}
public SPOptions SPOptions
{
get
{
if (_checkIsSecure())
return options2Factor.SPOptions;
return options1Factor.SPOptions;
}
}
public IdentityProviderDictionary IdentityProviders
{
get
{
if (_checkIsSecure())
return options2Factor.IdentityProviders;
return options1Factor.IdentityProviders;
}
}
public KentorAuthServicesNotifications Notifications
{
get
{
if (_checkIsSecure())
return options2Factor.Notifications;
return options1Factor.Notifications;
}
}
}
public class CustomCookieHandler : CookieHandler
{
private Func<bool> _checkIsSecure;
private CookieHandler _originalCookieHandler1Factor;
private CookieHandler _originalCookieHandler2Factor;
public CustomCookieHandler(Func<bool> checkIsSecure)
{
_checkIsSecure = checkIsSecure;
_originalCookieHandler1Factor = new ChunkedCookieHandler()
{
Name = "commonAuth",
RequireSsl = false
};
_originalCookieHandler2Factor = new ChunkedCookieHandler()
{
Name = "securedAuth",
RequireSsl = false
};
}
public override string MatchCookiePath(Uri baseUri, Uri targetUri)
{
if (_checkIsSecure())
return _originalCookieHandler2Factor.MatchCookiePath(baseUri, targetUri);
return _originalCookieHandler1Factor.MatchCookiePath(baseUri, targetUri);
}
protected override void DeleteCore(string name, string path, string domain, HttpContext context)
{
if (_checkIsSecure())
_originalCookieHandler2Factor.Delete();
else
_originalCookieHandler1Factor.Delete();
}
protected override byte[] ReadCore(string name, HttpContext context)
{
if (_checkIsSecure())
return _originalCookieHandler2Factor.Read();
return _originalCookieHandler1Factor.Read();
}
protected override void WriteCore(byte[] value, string name, string path, string domain, DateTime expirationTime, bool secure, bool httpOnly, HttpContext context)
{
if (_checkIsSecure())
_originalCookieHandler2Factor.Write(value, true, expirationTime);
else
_originalCookieHandler1Factor.Write(value, true, expirationTime);
}
}
In Global.asax file setting static properties to custom implementations. No more modifications needed.
protected void Application_Start()
{
FederatedAuthentication.FederationConfiguration.CookieHandler = new CustomCookieHandler(CheckIsSecure);
Kentor.AuthServices.Mvc.AuthServicesController.Options = new CustomOptions(CheckIsSecure);
}
private bool CheckIsSecure()
{
if (HttpContext.Current == null)
return false;
var mainHost = "http://host.local"; // host url
var sp = new [] { "/Home/Secure" }; // array of URLs which must be secured with other SP
var request = HttpContext.Current.Request;
var isSecured = sp.Any(x => x.Equals(request.Path, StringComparison.InvariantCultureIgnoreCase));
if (!isSecured && request.Path.Equals("/AuthServices/SignIn", StringComparison.InvariantCultureIgnoreCase))
{
var returnUrl = request.QueryString["ReturnUrl"];
isSecured = !string.IsNullOrEmpty(returnUrl) &&
sp.Any(x => x.Equals(returnUrl, StringComparison.InvariantCultureIgnoreCase));
}
if (!isSecured && request.Path.Equals("/AuthServices/Acs", StringComparison.InvariantCultureIgnoreCase))
{
var _r = new HttpRequestWrapper(request).ToHttpRequestData();
isSecured = _r != null && _r.StoredRequestState != null && _r.StoredRequestState.ReturnUrl != null
&& sp.Any(x => x.Equals(_r.StoredRequestState.ReturnUrl.ToString(),
StringComparison.InvariantCultureIgnoreCase));
}
if (!isSecured && !string.IsNullOrEmpty(request.Headers["Referer"]))
{
var referer = request.Headers["Referer"];
isSecured = sp
.Select(x => string.Format("{0}/{1}", mainHost.TrimEnd('/'), x.TrimStart('/')))
.Any(x => x.Equals(referer, StringComparison.InvariantCultureIgnoreCase));
}
return isSecured;
}

signalr self-host and static file server (e.g. owin.selfhost)

I have been "too" succesfully with my stand-alone Singular web service. We would like to now remove the IIS server, which does little other than serve about 10 JS/HTML/CSS files. Node.JS has a static-files plugin,
I looked and I saw that Katana, OWIN.SelfHost also has such a feature.
http://odetocode.com/blogs/scott/archive/2014/02/10/building-a-simple-file-server-with-owin-and-katana.aspx
Update
It was suggested to use the OWIN.Self-Host which has a feature, but I am unsure of where to put it in my existing code, and if it would effect the existing SIGNALR code (all Hubs share the same HTTP request calls, so I am also squeezing in Self-host on the same port, I wonder if that works). As well as it would be nice to use Scott Allen's (above referenced) example which also allows File Browsing.
Here is the code I current use to start up SIGNALR (V2.2) , which is run at the directly from the Main.cs file:
class Comm
{
public string url = "http://localhost:7700";
// string url = "http://*:7700"; // Requires admin privileges
public void start()
{
Task t = Task.Run(() =>
{
WebApp.Start<Startup>(url);
this.Clients = GlobalHost.ConnectionManager.GetHubContext<GatewayHub>().Clients;
Console.WriteLine("Server running on {0}", url);
Thread.Sleep(Timeout.Infinite);
});
}
public void send()
{
Clients.All.display("broadcast sent...");
}
private IHubConnectionContext<dynamic> Clients
{
get;
set;
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = (Tools.LogLevel >= 12);
hubConfiguration.EnableJavaScriptProxies = true;
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR("/signalr", hubConfiguration);
}
}
This answer is really from #Tracther, and I wish he would write it up so that I can credit him. But thanks to his input, here is what works for me. I did not need the commented lines. All I needed was to set the paths for /signlar and for the static FileSystem
}
class Startup
{
public void Configuration(IAppBuilder app)
{
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = (Tools.DebugLevel > 12);
hubConfiguration.EnableJavaScriptProxies = true;
app.UseCors(CorsOptions.AllowAll);
//app.UseStaticFiles();
app.UseFileServer(new FileServerOptions()
{
//RequestPath = new PathString("/Scopes"),
EnableDirectoryBrowsing = true,
FileSystem = new PhysicalFileSystem(#".\Scopes"),
});
app.MapSignalR("/signalr", hubConfiguration);
}
}

SignalR: How to call .Net client method from server?

I want to send data to my console application wich have a connection to my "someHub". I tried to do as described in example from a link but got no result.
Server side code:
[HubName("somehub")]
public class SomeHub : Hub
{
public override Task OnConnected()
{
//Here I want to send "hello" on my sonsole application
Clients.Caller.sendSomeData("hello");
return base.OnConnected();
}
}
Clien side code:
public class Provider
{
protected HubConnection Connection;
private IHubProxy _someHub;
public Provider()
{
Connection = new HubConnection("http://localhost:4702/");
_someHub = Connection.CreateHubProxy("somehub");
Init();
}
private void Init()
{
_someHub.On<string>("sendSomeData", s =>
{
//This code is not reachable
Console.WriteLine("Some data from server({0})", s);
});
Connection.Start().Wait();
}
}
What is the best solution for implementing this and what is the reason why i am not able to invoke the client method?
Are you trying to talk to clients outside of Hub? If yes then you will have to get a HubContext outside of Hub. And then you can talk all the clients.
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
SignalR Server using Owin Self Host
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:8081/";
using (WebApplication.Start<Startup>(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(3000);
context.Clients.All.addMessage("Current integer value : " + i.ToString());
}
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
// Turn cross domain on
var config = new HubConfiguration { EnableCrossDomain = true };
config.EnableJavaScriptProxies = true;
// This will map out to http://localhost:8081/signalr by default
app.MapHubs(config);
}
}
[HubName("MyHub")]
public class MyHub : Hub
{
public void Chatter(string message)
{
Clients.All.addMessage(message);
}
}
Signalr Client Console Application consuming Signalr Hubs.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://localhost:8081/");
var myHub = connection.CreateHubProxy("MyHub");
connection.Start().Wait();
// Static type
myHub.On<string>("addMessage", myString =>
{
Console.WriteLine("This is client getting messages from server :{0}", myString);
});
myHub.Invoke("Chatter",System.DateTime.Now.ToString()).Wait();
Console.Read();
}
}
To run this code, create two separate applications, then first run server application and then client console application, then just hit key on server console and it will start sending messages to the client.

Resources