How to share asp.net Session into WCF service - asp.net

Im using asp.net website with WCF service, having wsHttpBinding,Aspnet compatibility enabled, specified as Sessionmode -allowed, service behavior- isinitiated and client session cookie enabled. Its looking like Asp.Net session object and WCF Session( HTTPContext.Current.Session) work independently. How can I share Asp.net Session value to WCF Session and vise versa.

Instead of making your web service dependent on the hosting environment I would suggest you adding the needed parameter to the operation contract so that it is passed by the consumer which in your case is an ASP.NET application that will fetch it from the session.

in your service interface:
[ServiceContract]
public interface IService
{
[OperationContract]
string GetSessionValue();
[OperationContract]
void SetSessionValue(string value);
}
in your svc:
public class Service1 : IService
{
public string GetSessionValue()
{
return "your value";
}
public void SetSessionValue(string value)
{
// your code here
}
}
and finally consume that method from web code behind.

I searched a lot but could not find a way. Only option I found is use cookie enabled service in same virtual directory. Better to keep it as RESTful service

Look at "Managing shared cookies in WCF"

Related

How to set session use by asp.net web api with jquery (not use mvc)

I want to know how to set session using ASP.Net Web API (not ASP.net MVC) and jQuery.
Any idea?
Rule of thumb is not to use sessions with Web API due to the stateless nature of the web services. but you can access session modifying Global.ascx
file in the project.
protected void Application_PostAuthorizeRequest()
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
to set the same session between multiple servers you can use single SQL instance
as the session state.
then you can use that session inside your controller code
[HttpPost]
public string GetSetSession(string stringValue)
{
Session["session_key"]=stringValue;
return Session["session_key"].ToString();
}

How to get NTID in a service layer from IIS in .Net Core 2.0

Some background, I built my first .Net Core 2.0 API app that is hosted in a company intranet and used only by internal employees. The app needs to know who the user is on all pages, to work properly, but we don't want to add login/logout/authentication/sessions since the information doesn't need to be secured, it's only to personalize the user's data. I have enabled Windows Authentication successfully and I'm seeing the username (DOMAIN/USERNAME) displayed to the screen when I use the following in a controller:
User.Identity.Name
However, I wanted to get the same username (NTID) in my UserService instead, so that anytime the username is needed, any of the Services can call UserService to get the username.
I have tried all of the following in my UserService, but none of them provide the NTID from IIS:
...
return WindowsIdentity.GetCurrent().Name;
...
return System.Threading.Thread.CurrentPrincipal.ToString();
...
return Environment.UserName;
....
Since this is a REST API, I won't be using Views (I'm aware you can get the username in the View).
Is there an easy approach to get the username outside of the controller? I have found multiple examples online but they are all for < .Net Core 2.0.
In core, HttpContext is injected now, instead of being a thread static. That means the old style of using a static accessor like what you're trying won't work.
To access the HttpContext in something it is not automatically injected into (like a controller), you need to inject IHttpContextAccessor. For example:
public class UserService
{
protected readonly IHttpContextAccessor httpContextAccessor;
public UserService(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
...
}
Then, as long as you register your service via the ASP.NET Core DI container, an instance will be injected automatically into your service. You can then simply do:
var username = httpContextAccessor.HttpContext.User.Identity.Name;

How to restrict SignalR server connections?

I have a SignalR app. hosted in a Windows service (used OWIN & Katana as self hosting) and it's listening on mydomain.com:8080
On the same server, I also have an MVC application which is basically a website that connects to my SignalR hub which I mentioned above.
I want to restrict access to my SignalR app only to my MVC application. I've searched the internet but didn't come along an example of this.
Is it possible to achieve this? How can I get the information about if the connection is coming from my MVC app or from another app? Do I need to implement an authorization for my own MVC application to be able to connect to my SignalR application?
Right now, everyone on the internet can access to mydomain.com:8080/signalr endpoint which basically means a competitor can code a client that connects to my SignalR hub and use it. What are the options to prevent this scenario?
p.s: Please ask for more information -if you need- instead of just marking the post as "non constructive" because I don't know how this question can be asked more "constructive"
I believe I have a working example, it's quick and dirty, but it should do the job, and you should be able to expand it so it'll fit your needs better:
I created a class that inherits from Microsoft.AspNet.SignalR.AuthorizeAttribute and overrode the AuthorizeHubConnection method:
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthorize : AuthorizeAttribute
{
public override bool AuthorizeHubConnection(Microsoft.AspNet.SignalR.Hubs.HubDescriptor hubDescriptor, IRequest request)
{
string referer = request.Headers["Referer"];
string authority = new Uri(referer).Authority;
if (authority == "mydomain.com:8080")
{
return true;
}
return false;
}
}
all it does is check the Referer header's host/authority against a hard coded one, and returns true if they match.
You can then use it like this:
[CustomAuthorize]
public class ChatHub : Hub
{
//Hub code here...
}
If CustomAuthorize returns false, the request will stop there. The hub's OnConnected() will not be triggered.
Just Use cors option instead of writing code.in cors allow your domain only

Why is accessing session state and HttpContext in WebAPI considered bad design?

I have several .asmx web services that I want to upgrade to WebAPI. These web services look somewhat like this:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class TheWebService : System.Web.Services.WebService {
[WebMethod(EnableSession = true)]
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = HttpContext.Current.Session["UserSession"] as MySessionModel;
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
Basically, I have a single-page application. I'm using Forms Auth to login and redirect users to their "profile" and then, from this page, the app uses web services to communicate with the server. The web services only return raw strings so I don't need serialization at teh web service level. For the moment, the app is hosted in IIS and soon I'll be deploying it into azure.
I've looked around on the web, and several posts suggest that using session state and HttpContext is bad design. Why is using HttpCurrent and session state a bad idea in this case?
There is nothing innately wrong with using ASP.NET Session, as long as you don't use it as a catch-all basket for any old data. Shopping carts, for example, do not belong in Session: they belong in a Shopping Cart persistence component.
Also, and I suspect the reason for the Azure tag on this question, if you are running in a load-balanced environment such as an Azure Cloud Service, you need to use an external session provider such as a SQL Database or a shared cache. Using the in-process session provider (the default) will cause very odd, often unreproducable bugs as users are switched between different servers with different copies of the session.
As for HttpContext.Current, well, for Web API, things like Inversion of Control, Dependency Injection, and simple testability are important. A clean, testable Web API version of that service might look something like this:
public class TheWebService : ApiController {
private readonly IUserSession _userSession;
public TheWebService(IUserSession userSession)
{
_userSession = userSession;
}
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = _userSession.Get();
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
public interface IUserSession
{
MySessionModel Get();
}
You could still use HttpContext.Current.Session["UserSession"] in a class like this:
public class CurrentContextUserSession : IUserSession
{
public MySessionModel Get()
{
return HttpContext.Current.Session["UserSession"] as MySessionModel;
}
}
You would then use an IoC container such as Unity or Ninject to set CurrentContextUserSession as the implementation of IUserSession for Web API to use when constructing instances of TheWebService. But when you were writing your tests, you could use a mock or stub implementation of IUserSession that had no dependency on HttpContext.Current.
In your specific example, you are using the Session only inside the WebMethod, which is fine as it is already coupled to ASP.NET but many people tend to use this at other layers of their application which is a really bad design.
Common problems of using HttpContext.Current in those layers are:
the code cannot be easily unit tested in isolation
the code is tightly coupled to an ASP.NET context
This being said, having stateful services that depend on the session is bad design. In the example you have shown, that's an ASMX WebService which is depending on the ASP.NET Session state meaning that the client should be passing cookies around in order to invoke this service. Also stateful services are harder to scale.

ASP.NET Web API private controllers

I have an ASP.NET Web API project with two controllers, one of which I want to be publicly addressable over the internet and the other which I only want to be called internally over the network.
The best solution that I can come up with so far is to have a route template for public controllers and a template for internal: -
routeTemplate: "api/{controller}/{id}"
routeTemplate: "privateapi/{controller}/{id}"
That way I can configure IIS to block requests to the ‘privateapi’ route.
Is that the best way to handle this scenario?
Thanks.
The problem with controlling access MVC and WebAPI in IIS is that routing can sometimes make it difficult to see exactly which routes are ending up at your controller. It is perfectly valid (and in many cases preferred) to restrict access in the code as well.
To do this in code, you can do something like the following which uses a custom AuthorizeAttribute to filter out unauthorized users.
public class InternalAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.Properties.ContainsKey("MS_HttpContext"))
{
var ipAddress =
((HttpContextWrapper) actionContext.Request.Properties["MS_HttpContext"]).Request.UserHostAddress;
if (IsPrivateAddress(ipAddress))
{
return;
}
}
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Forbidden");
}
private bool IsPrivateAddress(string ipAddress)
{
// todo: verify ip address is in internal or otherwise whitelisted
}
}
You can then annotate your controller and have the filter applied on all actions in your controller.
[InternalAuthorize]
public class PrivateController : ApiController
{
}
Note: if the information/actions from this controller is particularly sensitive, you may want to deploy a version of your application that exposes this private api and blocks all traffic non from your whitelist rather than relying on application logic to keep bad guys out.
Use the Authorize Attribute:
[Authorize(Roles = "Admin")]
public class MyPrivateDataController :ApiController
You can't do this!
What you are doing is just creating another route for your controllers.
If they are deployed online they are accessible.
Now what you need is to deploy 2 different API's one at an external machine and another at an internal machine.

Resources