Session Variable in WCF Service - wcf

I am just creating a normal wcf service which get the Person object and returns the List. I need to save incoming Person object in a session and returns the list. I have implemented the code like below
[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
public class Service1 : IService1
{
public List<Person> getPerson(Person person)
{
List<Person> persons;
if (HttpContext.Current.Session["personList"] != null)
{
persons = (List<Person>)HttpContext.Current.Session["personList"];
}
else
{
persons = new List<Person>();
}
persons.Add(person);
HttpContext.Current.Session["personList"] = persons;
return persons;
}
}
But always i got only the object i passed in the parameter. Not the entire collection. So always session is returns null. What i missed?

The scope of the current session gets over immediately after the response is returned.
You need to create a session manager class.
Please see the working code below:-
[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
public class Service1 : IService1
{
public List<Person> getPerson(Person person)
{
SessionManager.PersonCollectionSetter = person;
return SessionManager.PersonCollectionGetter;
}
}
public static class SessionManager
{
private static List<Person> m_PersonCollection = new List<Person>();
public static Person PersonCollectionSetter
{
set
{
m_PersonCollection.Add(value);
}
}
public static List<Person> PersonCollectionGetter
{
get
{
return m_PersonCollection;
}
}
}

Your Service contract needs the following adornment
ServiceContract(SessionMode=SessionMode.Required)
however, do note that you can only maintain session state over a secured binding such as wsHttpBinding

Related

.NET Core 3.1 Complex Session Wrapper Not Working

I am trying to create a complex session wrapper in .NET Core 3.1. I ran into an issue where my variables are not being set. This is the way I set up the session wrapper class.
public class SessionWrapper : ISessionWrapper
{
private static IHttpContextAccessor context;
public SessionWrapper(IHttpContextAccessor _context)
{
context = _context;
}
public static Course Course
{
get
{
var key = context.HttpContext.Session.GetString("course");
if (key == null)
{
return default;
}
else
{
return JsonConvert.DeserializeObject<Course>(key);
}
}
set
{
if(value != null)
{
context.HttpContext.Session.SetString("course", JsonConvert.SerializeObject(value));
}
}
}
}
I configured my services to use session and the sessionwrapper.
services.AddDistributedMemoryCache();
services.AddSession();
services.AddHttpContextAccessor();
services.AddScoped<ISessionWrapper, SessionWrapper>();
I configured the pipeline to use session
app.UseSession();
In my controller, I am initializing course and set the session wrapper. Then, I am setting the course id to 4. It's not complaining, but the course id is not being set. It's always null. I've been looking at it for so and is getting frustrated. What am I missing here?
Course myCourse = new Course();
SessionWrapper.Course = myCourse;
SessionWrapper.Course.Id = "4"
I feel like your wrapper in itself isn't really the best approach to do this. A self-aware subclass of Course that has the 'know how' to store itself in Session, seems more logical to me. That way you are freeing your controller(s) from the responsibility for managing the persistence.
public abstract class Course
{
public abstract int Id { get; set; }
}
public class SessionCourse : Course
{
private int _id;
public override int Id
{
get => _id;
set { _id = value; UpdateSession(); }
}
// The GetCourse method is a factory for creating the SessionCourse objects
// and providing it with a ISession object so they can store themselves.
public static Course GetCourse(IServiceProvider services)
{
ISession session = services.GetRequiredService<IHttpContextAccessor>()?.HttpContext.Session;
SessionCourse course = session?.GetJson<SessionCourse>("Course") ?? new SessionCourse();
course.Session = session;
return course;
}
[JsonIgnore]
private ISession Session { get; set; }
private void UpdateSession() {
Session.SetJson("Course", this);
}
}
Now the trick is to satisfy requests for the Course object with the SessionCourse object that will store itself in session. You can do that by adding a scoped service with a lambda expression for the course object. The result is that requests for the Course service will return the SessionCourse object.
services.AddScoped<Course>(sp => SessionCourse.GetCourse(sp));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
So the benefit of creating this kind of service is that it allows you to simplify the controllers where Course objects are used.
public class CourseController : Controller
{
private Course course;
public CartController(Course courseService)
{
course = courseService;
}
public void SetCourseId()
{
course.Id = "4";
}
SessionExtension.cs defines extension methods for adding objects to the session.
public static class SessionExtensions {
public static void SetJson(this ISession session, string key, object value) {
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetJson<T>(this ISession session, string key) {
var sessionData = session.GetString(key);
return sessionData == null ? default(T) : JsonConvert.DeserializeObject<T>(sessionData);
}
}

Not able to find Property of a class of wcf service, while invoking service from client

I am returning a Hashtable, using a property from a wcf service, but in the client I am not able to find the property, help ME!!
This is my Service side code:
[ServiceContract]
public interface IService1
{
[OperationContract]
HashTable_Reference GetParametersWithDesk(String value);
}
[DataContract]
public class HashTable_Reference
{
Hashtable ht = new Hashtable();
public Hashtable htID
{
get { return ht; }
set { ht = value; }
}
}
This is my Client side code:
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
ServiceReference1.HashTable_Reference hr = new ServiceReference1.HashTable_Reference();
Hashtable ht = new Hashtable();
hr = client.GetParametersWithDesk("Sys12");
I need to access or get the Hashtable from the property of hr(object of the class)
Use DataMember attribute with your property to specifies that the member is part of a data contract.
[DataMember]
public Hashtable htID
{
get { return ht; }
set { ht = value; }
}

WCF avoiding too many endpoints for experts

I have a lot of businesses services already implemented, and I´m exposing them as services by WCF.
I don´t like the idea to have one endpoint to each service..... it could be a problem to maintain in the future as my repository grows.......
I´d like to know wcf´s experts opinions if the code below would be a good approach an them I can move ahead with this solution.
Business Service A:
[ServiceContract]
public interface IServiceA
{
[OperationContract]
object AddA(object a);
[OperationContract]
object Update();
}
Business Service B:
[ServiceContract]
public interface IServiceB
{
[OperationContract]
object AddB(object b);
[OperationContract]
object Update();
}
Concrete implementation for Service A
public class ConcreteServiceA : IServiceA
{
public object AddA(object a)
{
Console.WriteLine("ConcreateServiceA::AddA");
return null;
}
public object Update()
{
Console.WriteLine("ConcreateServiceA::Update");
return null;
}
}
Concrete implementation for Service B
public class ConcreteServiceB : IServiceB
{
public object AddB(object b)
{
Console.WriteLine("ConcreateServiceB::AddB");
return null;
}
public object Update()
{
Console.WriteLine("ConcreateServiceB::Update");
return null;
}
}
My single service is partial to separate concerns to each service.
Note that it´s constructors depends on both business services above, will be injection using IoC
Partial for constructors
public partial class WCFService
{
IServiceA _a;
IServiceB _b;
public WCFService()
: this(new ConcreteServiceA(), new ConcreteServiceB())
{
}
public WCFService(IServiceA serviceA, IServiceB serviceB)
{
_a = serviceA;
_b = serviceB;
}
}
Partial class implementing only IServiveA
public partial class WCFService : IServiceA
{
object IServiceB.AddB(object b)
{
return _b.AddB(b);
}
object IServiceB.Update()
{
return _b.Update();
}
}
Partial class implementing only IServiceB
public partial class WCFService : IServiceB
{
object IServiceA.AddA(object a)
{
return _a.AddA(a);
}
object IServiceA.Update()
{
return _a.Update();
}
}
And in the client side, I using like that:
var endPoint = new EndpointAddress("http://localhost/teste");
ChannelFactory<IServiceA> _factoryA = new ChannelFactory<IServiceA>(new BasicHttpBinding(), endPoint);
IServiceA serviceA = _factoryA.CreateChannel();
serviceA.Update();
var netTcpEndPoint = new EndpointAddress("net.tcp://localhost:9000/teste");
ChannelFactory<IServiceB> _factoryB = new ChannelFactory<IServiceB>(new NetTcpBinding(), netTcpEndPoint);
IServiceB serviceB = _factoryB.CreateChannel();
serviceB.Update();
I really appreciate any opinion or other suggestions.
There's nothing wrong with multiple endpoints - it's part of the process. What is wrong, however, is duplicating functionality over multiple endpoints. How many "UpdateThis's" or "AddThat's" developers need? This can get out of control and makes for a maintenance headache. Just look at your constructor, it will grow and grow as you add new services and consolidate them into one service.
Think coarse-grained not fine-grained.
As an alternative, maybe you can try passing request objects as a parameter and returning response objects. This approach may streamline your code and help you avoid the maintenance issues you mention in your post and gives you a suggestion.
So, it looks something like this:
// Your service will return a very generic Response object
public interface IService
{
Response YourRequest(Request request);
}
// Your service implementation
public partial class WCFService : IService
{
Response IService.YourRequest(Request request)
{
//inspect the Request, do your work based on the values
//and return a response object
}
}
// Your request object
public class Request()
{
object YourClass{get;set;}
DoWhat Action{get;set;} //enum, constants, string etc.
int ID {get; set;}
}
// Your response object
public class Response()
{
bool Success {get; set;}
}
// Create Request object
var request = new Request(){YourClass = YourClassName , Action DoWhat.Update(), ID=1};
// Your service call
var endPoint = new EndpointAddress("http://localhost/teste");
ChannelFactory<IService> _factory = new ChannelFactory<IService>(new BasicHttpBinding(), endPoint);
IService service = _factory.CreateChannel();
var response = service.YourRequest(request);
So, now you've removed the fine-grained approach and replaced it with course-grained one. Let me know if you'd like more detail.

DI in Service Contract WCF

Please find below my code. Employee class implements IEmployee interface.
namespace MiddleWare.ServiceContracts
{
[ServiceContract(Namespace = "http://mywebsite.com/MyProject")]
public interface IMiscellaneous
{
[OperationContract]
[ServiceKnownType(typeof(MiddleWare.Classes.Employee))]
IEnumerable<IEmployee> Search_Employee
(string SearchText);
}
namespace MiddleWare.ServiceClasses
{
public class Miscellaneous : IMiscellaneous
{
public IEnumerable<IEmployee> Search_Employee
(string SearchText)
{
List<IEmployee> emp = new List<IEmployee>();
IEmployee TempObject = (IEmployee)Activator.CreateInstance(typeof(IEmployee));
TempObject.EmployeeId = "12345678";
emp.Add(TempObject);
return emp;
}
}
}
As is visible the above code does compile but wont work because interface instance cannot be created.How can I achive DI(Dependency Injection) here...If I write..
IEmployee TempObject = (IEmployee)Activator.CreateInstance(typeof(Employee));
Then this class will be dependent not only on the Interface but also the class...assuming that one fine day Employee class becomes Employee2.There will be code changes at two places..
1)[ServiceKnownType(typeof(MiddleWare.Classes.Employee2))]
2)IEmployee TempObject = (IEmployee)Activator.CreateInstance(typeof(Employee2));
I want to avoid that. Can we do something at implementation of IOperationBehavior or is there a Ninject way of achieving this or am I trying to achieve impossible?
Consider a design change - Use the factory pattern to create an instance of your employee.
public EmployeeFactory : IEmployeeFactory
{
public IEmployee CreateEmployee()
{
return new Employee();
}
}
And introduce a dependency on the Factory from your middleware, so creating a new IEmployee becomes:
public class Miscellaneous : IMiscellaneous
{
private readonly IEmployeeFasctory _employeeFactory;
public class Miscellaneous(IEmployeeFactory employeeFactory)
{
_employeeFactory = employeeFactory;
}
public IEnumerable Search_Employee (string searchText)
{
List employees = new List();
IEmployee employee = _employeeFactory.CreateEmployee();
employee.EmployeeId = "12345678";
employees.Add(TempObject);
return employees;
}
And then you can inject your EmployeeFactory into Miscellaneous. And should Employee one day become deprecated and Employee2 comes along, just change the factory!
As rich.okelly points out in another answer, IEmployeeFactory should be used to create instances of the IEmployee interface, since IEmployee isn't a Service, but an Entity.
The IEmployeeFactory interface, on the other hand, is a Service, so should be injected into the service class using Constructor Injection. Here's a write-up of enabling Constructor Injection in WCF.
Had a discussion within the team.
1) Constructor based implementation is not comfortable..The service would be IIS hosted and consumed as a web-reference.Cannot ask client systems to provide FactoryImplementatedObjects in Miscellaneous class call.
2) Entity based factories is also not absolutely accurate.If I happen to have say 20 specific entities in my project like Employee,Material,Project,Location,Order then I need to have 20 Factories.Also the Miscellaneous class will have several custom constructors to support specific contract calls..
I have prepared a system which is working and DI is achieved to a great level but I feel like I am cheating OOPS..Doesnt feel correct at heart..but cannot be refuted to be wrong..Please check and let me know your comments.
I now have a IEntity Interface which is the base for all other Entities.
namespace BusinessModel.Interfaces
{
public interface IEntity
{
string EntityDescription { get; set; }
}
}
Hence forth all will implement this.
namespace BusinessModel.Interfaces
{
public interface IEmployee : IEntity
{
string EmployeeId { get; set ; }
}
}
namespace BusinessModel.Interfaces
{
public interface IProject : IEntity
{
string ProjectId { get; set; }
}
}
and so on..(Interface implementing interface..absolutely ridiculous,cheating but working)
Next,An Enum type is declared to have a list of all Entities...
namespace MiddleWare.Common
{
internal enum BusinessModel
{
IEmployee,
IProject
}
}
A DI Helper class is created which will henceforth be considered a part of Business Model and any changes to it (Implementation,Naming..) would be taken as a Business Shift.So if DIHelper class has to become DIHelper2 then this is like BIG.(Can this also be avoided??)
namespace MiddleWare.Common
{
internal sealed class DIHelper
{
internal static IEntity GetRequiredIEntityBasedObject(BusinessModel BusinessModelObject)
{
switch (BusinessModelObject)
{
case BusinessModel.IEmployee:
return new Employee();
}
return null;
}
}
}
Function is Self Explanatory...
So now finally,the contract and implementation...
namespace MiddleWare.ServiceContracts
{
[ServiceContract(Namespace = "http://mywebsite.com/MyProject")]
public interface IMiscellaneous
{
[OperationContract]
[ServiceKnownType(typeof(MiddleWare.Classes.Employee))]
IEnumerable<IEmployee> Search_Employee
(string SearchText);
}
}
namespace MiddleWare.ServiceClasses
{
public class Miscellaneous : IMiscellaneous
{
public IEnumerable<IEmployee> Search_Employee
(string SearchText)
{
List<IEmployee> IEmployeeList = new List<IEmployee>();
IEmployee TempObject = (IEmployee)DIHelper.GetRequiredIEntityBasedObject(MiddleWare.Common.BusinessModel.IEmployee);
TempObject.EmployeeId = "12345678";
IEmployeeList.Add(TempObject);
return IEmployeeList;
}
}
}
What do you say??
My Team is happy though :)
From your updated requirements, there is nothing related to DI in this question...
So, to create a type based on the service known types of a service contract you can use:
public class EntityLoader<TServiceContract>
{
private static readonly HashSet<Type> ServiceKnownTypes = new HashSet<Type>();
static EntityLoader()
{
var attributes = typeof(TServiceContract).GetMethods().SelectMany(m => m.GetCustomAttributes(typeof(ServiceKnownTypeAttribute), true)).Cast<ServiceKnownTypeAttribute>();
foreach (var attribute in attributes)
{
ServiceKnownTypes.Add(attribute.Type);
}
}
public TEntity CreateEntity<TEntity>()
{
var runtimeType = ServiceKnownTypes.Single(t => typeof(TEntity).IsAssignableFrom(t));
return (TEntity)Activator.CreateInstance(runtimeType);
}
}
Which is then useable like so:
[ServiceContract(Namespace = "http://mywebsite.com/MyProject")]
public interface IMiscellaneous
{
[OperationContract]
[ServiceKnownType(typeof(Employee))]
IEnumerable<IEmployee> SearchEmployee(string SearchText);
}
public class Miscellaneous : IMiscellaneous
{
private readonly EntityLoader<IMiscellaneous> _entityLoader = new EntityLoader<IMiscellaneous>();
public IEnumerable<IEmployee> SearchEmployee(string SearchText)
{
List<IEmployee> employees = new List<IEmployee>();
IEmployee employee = _entityLoader.CreateEntity<IEmployee>();
employee.EmployeeId = "12345678";
employees.Add(employee);
return employees;
}
}
Obviously, the above code assumes that ALL of your service entities will contain public parameterless constructors and that there will only be one ServiceKnownType that implements each interface.

No Response from WCF with Entity Framework objects

Ok, i have the following object I pass back when someone calls "Authenticate" on my WCF Service (using http).
[DataContract]
public sealed class SecurityContext
{
private Guid _tolken;
private User _user;
private ICallbackContract _callbackContract;
[IgnoreDataMember]
public ICallbackContract CallbackContract
{
get { return _callbackContract; }
}
[DataMember]
public User User
{
get { return _user; }
set { _user = value; }
}
[DataMember]
public Guid Tolken
{
get { return _tolken; }
set { _tolken = value; }
}
public SecurityContext(Guid tolken, User user, ICallbackContract callbackContract)
{
Asserter.IsNotNullArgument(tolken, "tolken");
Asserter.IsNotNullArgument(user, "user");
Asserter.IsNotNullArgument(callbackContract, "callbackContract");
_tolken = tolken;
_user = user;
_callbackContract = callbackContract;
}
}
For some reason, when i make the Async call, it times out and I never get a response, but when i comment out the User object (which is a Entity Framework object) it works fine.
Anyone ever experience this before?
Ok, so i figured out what the problem was. Apparently the entity model is set to Lazy load by default. This was causing issues with the data being HUGE when it was sent to the client...
I solved the issue by doing this during the entity model creation...
_entities.ContextOptions.LazyLoadingEnabled = false;
is User class have DataContract attribute?