Using custom route in WCF service hosted in an ASP.NET application - c#

I have this simple service in my ASP.NET application:
// IBilling.cs
namespace WebApplication3.V1 {
[ServiceContract]
public interface IBilling {
[OperationContract]
string Get();
}
}
// Billing.svc
namespace WebApplication3.V1 {
public class Billing : IBilling {
public string Get() { return "Amiry"; }
}
}
It's accessible (by default) through /V1/Billing.svc route. However, I changed the route by adding this simple line to my route-table:
RouteTable.Routes.Add(
new ServiceRoute("api/ws/v1/billing",
new WebServiceHostFactory(),
typeof(Billing)));
Now, I can execute the Get() method and get result:
// it works:
http://localhost:7475/api/ws/v1/billing/get
BUT, the discovery address is not accessible:
http://localhost:7475/api/ws/v1/billing
// returns "Endpoint not found."
I'm pretty new to WCF services; so I have no idea where the problem could be and googling didn't help. Can you guide me to achieve the route I mentioned above please? Thanks in advance.

Related

Attribute To Secure Web Api

I am working with a web api where it should have a request key and depending upon it, the api controller will do
specific task. I am using rest client program in vs code and did the following for testing:
GET http://localhost:PortNo/WeatherForecast/GetAllTeams
test: "12345678910" //Key
So in the controller, I did this to get the key value:
[HttpGet]
public async Task<ActionResult<IEnumerable<TeamDetails>>> GetAllTeams()
{
string Token = Request.Headers["test"]; //Getting the key value here
var teams = _service.GetAllTeams();
return Ok(teams)
}
But I've few things in mind and doing R & D like how can I make the above with an attribute. Say each controller
will have an attribute as follows and make the request invalid if no proper key found:
[InvalidToken] //This is the attribute
[HttpGet]
public async Task<ActionResult<IEnumerable<TeamDetails>>> GetAllTeams()
{
var teams = _service.GetAllTeams();
return Ok(teams)
}
I am not sure if this is going to make the api secure and my plan is to valid every http request (In my case, a simple form submission at the moment), so it should say the request is generated from the web api app.
N.B: I worked with web api earlier in small sections but now a broader thing to implement, so expecting few suggestions that can help me to guide for better design.
try it:
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
..
public class InvalidToken : Attribute, IActionFilter
{
public InvalidToken( )
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var Authorization = context.HttpContext.Request.Headers["test"];
if ( Authorization != "12345678910")
{
context.ModelState.AddModelError("Authorization", "Authorization failed!");
return;
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// "OnActionExecuted"
}
}
Startup.cs
services.AddScoped<InvalidToken>();
// add filter to whole api
services.AddControllers(options =>
{
options.Filters.Add<InvalidToken>();
});

WCF Services: Requests are limited to a single "Request" Paramater

I have a very strange and obscure issue with WCF services that I was hoping to get some insight on:
I am working a WCF service that we are building to replace one that we no longer have source code for. For some reason, in the new WCF service, everything is forced through a single paramater called "request". Using the WCF test client, this is what it looks like
On the "correct" service, this is what it looks like:
Is there any reason why this would be happening? I've defined all of the requests as follows:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string SomeRequest();
}
Which seems correct, but there may be something I've overlooked that is causing this.
In your original WCF service, there is a request function parameter, and it has a definition similar to the following:
[ServiceContract]
public interface IMyService
{
[OperationContract]
Request SomeRequest(Request request);
}
[DataContract]
public class Request
{
string documentId;
[DataMember]
public string DocumentId
{
get { return documentId; }
set { documentId = value; }
}
}
In the new wcf service:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string SomeRequest(string documentId);
}
So this is because the function parameters are different. Originally your parameter was class, but later changed to string, so the display in WCFTestClient is different.

how to add delegate class for service manager class when calling soap service in c#?

First of all, I want to share my scenario what i want to build -
Scenario:
I am building a client app using wpf. In some cases, I need to call a web service to get data from the server. In order to do this, I added a web reference using wsld url. And I created a ServiceManager class that will call service method. For security reason, I need to add some header info at soap xml request for example, UserToken, SAML Token and so on. I can this from my ServiceManager class. But I want to add another class which will be called before sending request to the server. In that class, I will do something like adding security header to soap xml request with request and then send it to the server.
I used SOAP Extension to fulfill my purpose and it works well. But the problem is, every-time I need to add annotation in Reference.cs (for each web service reference) file at top of the service method. I believe that there is some other easiest way to make this working better than SOAP Extension. Is there any way where I can only call the service and a delegate class will be called automatically and I don't need to add any annotation to the reference file? I will share my sample code here.
ServiceManage class:
public class ServiceManager
{
public UserDataService dataService; //web service added at Web Reference
public ServiceManager()
{
dataService = new UserDataService();
getUserServiceRequest rqst = new getUserServiceRequest();
getUserServiceResponse resp = dataService.getUser(rqst);
}
}
Reference.cs
[TraceExtensionAttribute(Name = "First")]
public getUserServiceResponse getUser([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] getUserServiceRequest request) {
object[] results = this.Invoke("getUser", new object[] {
request});
return ((getUserServiceResponse)(results[0]));
}
TraceExtensionAttribute.cs
[AttributeUsage(AttributeTargets.Method)]
public class TraceExtensionAttribute : SoapExtensionAttribute
{
private string mstrName = null;
public override Type ExtensionType
{
get { return typeof(TraceExtension); }
}
public override int Priority
{
get { return 1; }
set { }
}
public string Name
{
get { return mstrName; }
set { mstrName = value; }
}
}
TraceExtension.cs
public class TraceExtension : SoapExtension
{
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attr){//..do something}
public override void Initialize(object initializer){//..do something}
public override Stream ChainStream(Stream stream){//...do something}
public override void ProcessMessage(SoapMessage message) {//..do something}
}
Finally, I found the solution. Just through out Web Reference and add Service Reference instead. Then go to the following link. It works for me.

ASP.NET Web API - Change database application is running to based on HTTP header information

I have started a new Web API project that requires that we switch the database the application is running to based on HTTP header information sent to the API. The application user will be identified by a HTTP header and the application should then change to use their database.
I have a base controller CrudControllerBase<T> ( to handle simple generic HTTP requests ) which creates a DataService<T> in it's constructor. All of my controllers will derive from this base controller and will have access to this DataService. The DataService is used to do common DB queries ( FindById(), FindAll(), etc. ) and more complex queries are bolted on using extension methods.
public abstract class CrudControllerBase<T> : ApiController where T : class, IEntity
{
protected IDataService<T> _dataService;
public CrudControllerBase()
{
this._dataService = new DataService<T>();
}
[HttpGet]
public virtual async Task<IHttpActionResult> Get(Guid id)
{
var model = await _dataService.FindByIdAsync(id);
return Ok<T>(model);
}
//code left out
}
public class OrdersController : CrudControllerBase<OrderItem>
{
}
and in the DataService I new up the DbContext class:
public class DataService<T> : IDataService<T> where T:class, IEntity
{
private readonly AppDbContext _context;
public DataService()
{
_context = new AppDbContext(); // need to pass in connection string
}
// code left out
}
I need to be able to pass in the connection string to the constructor of AppDbContext but in the constructor of CrudControllerBase I do not have access to the HttpRequestMessage to be able to pass this info to the DataService.
Can anyone suggest a solution ? I am quite happy to try a completely different way of doing this if someone can suggest something. Thanks !
OK so I have got this working. It may not be the best solution but it works and if anyone has any feedback / improvements then please share. Thanks to #AaronLS for pointing me in the right direction. This article also helped a lot.
The first step was to create a CustomControllerFactory that implements the IHttpControllerActivator interface. This gives you a Create method in which you can write your own code for newing up your Controllers. This is my CustomControllerFactory where I new up my controller passing in the HTTP Header as a string:
public class CustomControllerFactory : IHttpControllerActivator
{
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var schemaKey = request.Headers.Where(k => k.Key == "schema").FirstOrDefault().Value.FirstOrDefault();
return (IHttpController)Activator.CreateInstance(controllerType, new string[] { schemaKey });
}
}
The next step is to tell the web API to use this method for instantiating controllers. To do this I added this line to my WebApiConfig class:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new CustomControllerFactory());
The last thing I needed to was add a constructor to each controller which took in the string value and passed it to the base controller
public OrdersController(String databaseName) : base(databaseName) { }
and my base controller passes the parameter to the DataService
public CrudControllerBase(String databaseName)
{
this._dataService = new DataService<T>(databaseName);
}
and my database passes in the connection string to the AppDbContext() constructor
public DataService(String databaseName)
{
this._context = new AppDbContext(BuildConnectionString(databaseName));
}
I realise there is no error handling / security checking yet but I will add that in :-)

integrating unity.wcf with asp.net routes

I am trying to use unity.wcf inside my wcf web services without an svc file.
My code:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
//[BasicAuthentication] TODO: this need to be set up
public class SsoAuthenticationService : ISsoAuthenticationService
{
private readonly ICustomerManager _manager;
internal const string ServiceUri = "SsoAuthenticationService";
public SsoAuthenticationService(ICustomerManager manager)
{
_manager = manager;
}
[WebGet(UriTemplate = "CreateSsoLogin/{request}")]
public ServiceResponse<bool> CreateSsoLogin(string request)
{
// TODO: inputs and outputs are wrong
_manager.DoWork();
return new ServiceResponse<bool>();
}
}
public class ServiceFactory : UnityServiceHostFactory
{
protected override void ConfigureContainer(Microsoft.Practices.Unity.IUnityContainer container)
{
container.RegisterType<ISsoAuthenticationService, SsoAuthenticationService>("authentication")
.RegisterType<ICustomerManager, CustomerManager>();
}
}
Now the problem comes when I try and connect the ServiceFactory class - in all the code examples I have seen they do this via an svc file, but I don't have one in my application, as it is using ASP.NET routing.
So my Global.asax looks like:
private static void RegisterRoutes(RouteCollection routes)
{
//Integrate WCF services with the ASP.NET routing feature
routes.Add(new ServiceRoute(SsoAuthenticationService.ServiceUri, new ServiceFactory(), typeof(SsoAuthenticationService)));
}
When I call my web service method, I am not hitting the web method code (it does call ServiceFactory.ConfigureContainer though). If I weren't using Unity, the Global.asax would look like:
private static void RegisterRoutes(RouteCollection routes)
{
//Integrate WCF services with the ASP.NET routing feature
routes.Add(new ServiceRoute(SsoAuthenticationService.ServiceUri, new WebServiceHostFactory(), typeof(SsoAuthenticationService)));
}
And if I change it to this, then the web method is hit, but of course it complains about the constructor.
What extra configuration do I need to make the ServiceFactory class behave like WebServiceHostFactory?
Or would a better option be to not use Unity.Wcf, and try and implement with plain Unity?
OK, I have managed to find the answer to this using the following link http://www.agile-code.com/blog/rest-web-services-with-unity-wcf/
I had to create a new pair of classes to inherit from WebServiceHostFactory (abstract) and WebServiceHost as described in the link.
Once these were in place, and my ServiceFactory class inherited from the new class, everything started working.

Categories