I have a SignalR Hub subclass, where I keep a static list of users that joined the hub. Is there a need for locking that list in methods where it is used, and what is a proper way to do this - is this a proper way to do this?
public class MessageHub : Hub
{
private static List<HubUser> users = new List<HubUser>();
public void Join(string UserName)
{
lock(users){/*some code to validate and store user*/}
}
public List<HubUser> GetOnlineUsers()
{
lock (users)
{
return users.ToList<HubUser>();
}
}
//other methods such as GetUsersCount(), IsUserOnline(string User)....
}
Related
So just some background on how the current UI automation solution works -
Our application is a Windows WPF app, so we utilize WinAppDriver for our automated testing needs. The solution for this is very similar to your typical UI automation page object design. We have page objects that reference elements, and then in our tests we call the methods from these page objects to perform actions on the host. The page objects make use of the C# partial classes. One class to store elements, one class to use these elements and perform actions
The test classes all inherit from a TestClassBase that handles the StartUp and TearDown login. So current design for something like a Login page and a test class that interacts with it looks like this
Login.Elements.cs
namespace UITesting
{
public partial class Login
{
public WindowsElement usernameField => _session.FindElementByAccessibilityId("UserName");
public WindowsElement passwordField => _session.FindElementByAccessibilityId("Password");
public WindowsElement signInButton => _session.FindElementByAccessibilityId("Sign In");
}
}
Login.Actions.cs
namespace UITesting
{
public partial class Login
{
// Driver Setup
private readonly WindowsDriver<WindowsElement> _session;
public Login(WindowsDriver<WindowsElement> session) => _session = session;
// Enter Username
public void EnterUsername(string username)
{
usernameField.SendKeys(username);
}
// Enter Password
public void EnterPassword(string password)
{
passwordField.SendKeys(password)
}
// Click 'Sign In'
public void SignIn()
{
signInButton.Click();
}
}
}
LoginTests.cs
namespace UITesting.Test
{
[Category("Login Tests")]
class LoginTests : TestClassBase
{
[Test]
public void Login()
{
// Login
login.EnterUsername("TestUser1");
login.EnterPassword("Password");
login.ClickSignIn();
}
}
}
TestClassBase
namespace UITesting
{
[TestFixture]
public class TestClassBase
{
// Declare Page Ogjects
public Login login;
// Declare WinAppDriver Session
private WindowsDriver<WindowsElement> session;
[SetUp]
public void SetUp()
{
// Instantiate Page Objects
login = new Login(session);
// Additional SetUp Logic here...
}
[TearDown]
public void TearDown()
{
// TearDown Logic here...
}
}
}
This all works well and great, but what I am trying to do is evolve this into is something that can run the exact same test using the same code on a different host.
We also have a Web version of the app that utilizes the Uno platform. The app is pretty much identical on the web, but to automate it we need to use Selenium. What I don't want to do is to have to manage two separate UI automation solutions, and since the two versions of the app are pretty much identical, I want to be able to toggle the target platform that the tests run on in our CI/CD pipeline and this will ultimately change what code is getting executed.
So it seems like utilizing Interfaces is probably the way to go here, and I understand that using them it would be possible to now have a Page Object class structure like below
ILogin.cs
LoginWeb.Actions.cs
LoginWeb.Elements.cs
LoginWPF.Actions.cs
LoginWPF.Elements.cs
This way, I now have 4 partial classes where the Actions classes inherit the interface and they use the elements from their corresponding Elements class.
The part that I don't understand is how I can get the test class to now execute the code from the desired Actions class. The part where I instantiate the page objects is key, as in this example both the WPF and Web page object would need to share the name login. Would I have to create two different TestClassBase classes and some sort of Interface for them and have the tests inherit both? Or am I just going about this the completely wrong way..
This might be a larger refactoring job, but it will be worth the effort.
First, you'll need to create interfaces for each page model. I recommend keeping the interfaces as simple as possible in order to provide a complete and flexible abstraction. Instead of three separate methods (EnterUsername, EnterPassword and ClickSignIn) which must be called in a specific order, consider a single method called SignIn which accepts a username and password as arguments. The method will internally handle entering the username, password and clicking the appropriate button.
Really, if you go this route, think hard about the interfaces. Try to avoid any situation where the order methods are called matters. Try to focus on the use case, and not the steps required to satisfy that use case.
public interface ILoginPage
{
void SignIn(string username, string password);
}
Next, implement this interface on two different classes. Each class will specialize in Selenium or WinAppDriver. Consider using a naming convention where page models that deal with the web application are prefixed with "Web" and page models for the desktop app are prefixed with "Windows" or "Desktop".
public class WebLoginPage : ILoginPage
{
private readonly IWebDriver driver;
public WebLoginPage(IWebDriver driver)
{
this.driver = driver;
}
public void SignIn(string username, string password)
{
// Enter username
// Enter password
// Click sign-in button
}
}
public class DesktopLoginPage : ILoginPage
{
private readonly WindowsDriver<WindowsElement> session;
public DesktopLoginPage (WindowsDriver<WindowsElement> session)
{
this.session = session;
}
public void SignIn(string username, string password)
{
// Enter username
// Enter password
// Click sign-in button
}
}
Once you have a proper abstraction, you will need an interface for a factory class that creates page models, and then two implementing classes:
public interface IPageModelFactory
{
ILoginPage CreateLoginPage();
}
public class WebPageModelFactory : IPageModelFactory
{
private readonly IWebDriver driver;
public PageModelFactory(IWebDriver driver)
{
this.driver = driver;
}
public ILoginPage CreateLoginPage()
{
return new WebLoginPage(driver);
}
}
public class DesktopPageModelFactory : IPageModelFactory
{
private readonly WindowsDriver<WindowsElement> session;
public DesktopPageModelFactory(WindowsDriver<WindowsElement> session)
{
this.session = session;
}
public ILoginPage CreateLoginPage()
{
return new DesktopLoginPage(session);
}
}
This is an implementation of the Abstract Factory Pattern, and is an approach you can take without resorting to class reflection. While class reflection would probably take less code, it is much more difficult to understand. Just for giggles, here is an attempt at class reflection to generate page models:
public class PageModelFactory
{
private readonly object client;
public PageModelFactory(object client)
{
this.client = client;
}
public ILoginPage CreateLoginPage()
{
var pageModelType = GetPageModelType<ILoginPage>();
var constructor = pageModelType.GetConstructor(new Type[] { client.GetType() });
return (ILoginPage)constructor.Invoke(new object[] { client });
}
private Type GetPageModelType<TPageModelInterface>()
{
return client.GetType()
.Assembly
.GetTypes()
.Single(type => type.IsClass && typeof(TPageModelInterface).IsAssignableFrom(type));
}
}
You can use it with either driver:
// Selenium
var driver = new ChromeDriver();
// WinApDriver (however you initialize it)
var session = new WindowsDriver<WindowsElement>();
PageModelFactory webPages = new PageModelFactory(driver);
PageModelFactory desktopPages = new PageModelFactory(session);
ILoginPage loginPage = null;
loginPage = webPages .CreateLoginPage();
loginPage.SignIn("user", "...");
loginPage = desktopPages.CreateLoginPage();
loginPage.SignIn("user", "...");
Unless you or your team are comfortable with class reflection, I would recommend the abstract factory pattern approach, just because it is easier to understand.
Either way, you will need to determine which client you are using (web versus desktop). This should be done in a the setup method for your test. Refactoring your tests into a base class to centralize this decision making code is advised.
Scenario: I have a console application which references couple of class libraries. ClassLibEmployee pulls the data from SQL database and returns a List. I need to loop through the list of Employee's and send that to a WebAPI and update SQL DB with status. I created ClassLibPay which a wrapper for WebAPI.
ClassLibEmployee.EmployeeData ed = new ClassLibEmployee.EmployeeData();
var elist = ed.PullEmployees();
foreach (Employee e in elist) {
bool stat = ClassLibPay.ServiceWrap.Sendtopay(e.Id, e.Name, e.Pay, e.ExemptFlag, e.Hours);
ed.ChageStatus(e.Id, e.Name, e.Pay, e.ExemptFlag, e.Hours, stat);
}
In ClassLibEmployee, I defined class as public class EmployeeData
In ClassLibPay, I defined class as public static class ServiceWrap
Questions:
since I will be calling ChangeStatus method in EmployeeData for each employee, should that be a static class?
ServiceWrap is calling a service, is there a way to avoid creating instance of the service, for every Sendtopay call?
Console App
--References ClassLibEmployee
public class EmployeeData
{
public List<Employee> PullEmployees()
{
}
}
ConsoleApp
--References ClassLibPay
-- ClassLibPay calls a WebAPI
public static class ServiceWrap
{
public static bool Sendtopay(int id, string name, decimal pay, bool flg, int hours)
{
using (EDataSvc service = new EDataSvc())
{
service.serviceMethod(id,name,pay,flg,hours);
}
}
}
To prevent creating every time class, you definitely should move to DI way as Michael said.
This is very simple example how to use DI with console application based on Autofac library. Below we have Main console application and two classes where one is our wrapper(where maybe you want to prepare your data, and eDataService which should just send data to back-end. We register both classes as PerLifeTimeScope(here, this is singleton's - in another words have only one instance if we get it from the DI container). Of course you can choose ready frameworks with already integrated DI containers.
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
builder.RegisterType<EDataSvc>().InstancePerLifetimeScope();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<MyService>();
service.MakeRequestAsync("test");
}
}
}
public class EDataSvc
{
public void SendRequestAsync()
{
//TODO:Send request
}
}
public class MyService : IMyService
{
private EDataSvc _eDataService;
public void MakeRequestAsync(EDataSvc eDataSvc)
{
_eDataService = eDataSvc;
}
public void MakeRequestAsync(string parameter)
{
//TODO prepare your data or additional logic
_eDataService.SendRequestAsync();
}
}
public interface IMyService
{
void MakeRequestAsync(string parameter);
}
Below is the order process which i have implemented thorough signalR in asp.net core web api. Every thing is working fine except one scenario(Problem scenario given below) i need the best possible solution.
System Overview:
1) Customer Place new order (Client wait until order being processed by admin client).
2) The order is saved to the DB with ‘status=unknown ‘.
3) Admin is notified through hub about new order. (on a dashboard)
4) Admin accepts or decline new order then Order status is updated in database.
5) Customer is notified about the order, if is accepted or declined through SignalR
Problem scenario
The business rule that we have to implement is that the order should be automatically declined after 2 minutes if the Admin does not respond. In this case the server should automatically decline the order and the customer should be notified.
Solution 1: We thought of adding a timer on the Customer and Admin side, but we prefer the Timer to be somewhere on the server so we don't have to implement the timers on the customer and admin side.
Base Hub Controller
public abstract class ApiHubController<T> : Controller
where T : Hub
{
private readonly IHubContext _hub;
public IHubConnectionContext<dynamic> Clients { get; private set; }
public IGroupManager Groups { get; private set; }
protected ApiHubController(IConnectionManager signalRConnectionManager)
{
var _hub = signalRConnectionManager.GetHubContext<T>();
Clients = _hub.Clients;
Groups = _hub.Groups;
}
}
public class BaseHubController : ApiHubController<Broadcaster>
{
public BaseHubController(IConnectionManager signalRConnectionManager) : base(signalRConnectionManager)
{
}
}
Server side code (Place Order)
public class OrderController : BaseHubController
{
public async Task SendNotification([FromBody]NotificationDTO notify)
{
await Clients.Group(notify.AdminId.ToString()).SendNotificationToDashboard(notify); //notifing to admin for about //new order
}
public async Task NotifyDashboard(NotificationDTO model)
{
var sendNotification = SendNotification(model);//sending notification to admin dashboard
}
[HttpPost]
[Route("PlaceOrder")]
public IActionResult PlaceOrder([FromBody]OrderDTO order)//Coustomer place order
{
if (!ModelState.IsValid)
{
return new BadRequestObjectResult(ModelState);
}
var orderCode = _orderProvider.PlaceOrder(order, ValidationContainer);//save new order in database
var notify = order.GetNotificationModel();
notify.OrderId = orderCode;
NotifyDashboard(notify);
//Other code
return new OkObjectResult(new { OrderCode = orderCodeString, OrderId = orderCode });
}
}
I have this api client ICommunicationClient(url, tenant) registered in my IoC container. Now I'm facing the scenario where I can have 1 to n api clients. I need to register all of them and I'm not sure how to handle that. I've seen there's this RegisterCollection in SI though.
I'm considering use a ICommunicationClientProvider as a wrapper around the actual clients. It contains a list with all the registered clients and methods to retrieve them. I feel this is not the best approach and of course, it "forces" me to touch other pieces of the app.
public class CommunicationClientProvider : ICommunicationClientProvider
{
public CommunicationClientCollection CommunicationClientsCollection { get; set; }
public string Tenant { get; set; }
public ICommunicationClient GetClients()
{
return CommunicationClientsCollection[Tenant];
}
public void SetClients(CommunicationClientCollection clients)
{
CommunicationClientsCollection = clients;
}
}
public interface ICommunicationClientProvider
{
ICommunicationClient GetClients();
void SetClients(CommunicationClientCollection clients);
}
This to host the collection
public class CommunicationClientCollection : Dictionary<string, ICommunicationClient>
{
}
Here I register the collection against SI
var clients = new CommunicationClientProvider();
foreach (var supportedTenant in supportedTenants)
{
clients.CommunicationClientsCollection
.Add(supportedTenant, new CommunicationClient(
new Uri(configuration.AppSettings["communication_api." + supportedTenant]),
new TenantClientConfiguration(supportedTenant)));
}
container.RegisterSingleton<ICommunicationClientProvider>(clients);
Do you know a better way of doing this? This is a normal scenario for example when you have multiple databases.
UPDATE: - ITenantContext part -
This is basically how my tenant context interface looks like:
public interface ITenantContext
{
string Tenant { get; set; }
}
and this is where I'm making my call to communication api:
public class MoveRequestedHandler : IHandlerAsync<MoveRequested>
{
private readonly IJctConfigurationService _communicationClient;
private readonly ITenantContext _tenantContext;
public MoveRequestedHandler(IJctConfigurationService communicationClient, ITenantContext tenantContext)
{
_communicationClient = communicationClient;
_tenantContext = tenantContext;
}
public async Task<bool> Handle(MoveRequested message)
{
_tenantContext.Tenant = message.Tenant;
_communicationClient.ChangeApn(message.Imei, true);
return await Task.FromResult(true);
}
}
here I register the ITenantContext
container.RegisterSingleton<ITenantContext, TenantContext>();
The tenant is defined within the MoveRequested object (message.Tenant).
How can I make CommunicationClient aware of that tenant?
If adding an ICommunicationClientProvider abstraction causes you to make sweeping changes throughout your application, there is clearly something wrong. You should typically be able to add features and make changes without having to do sweeping changes. And as a matter of fact, I think your current design already allows this.
Your ICommunicationClientProvider) acts like a factory, and factories are hardly ever the right solution. Instead, your are much better of using the Composite design pattern. For instance:
sealed class TenantCommunicationClientComposite : ICommunicationClient
{
private readonly ITenantContext tenantContext;
private readonly Dictionary<string, ICommunicationClient> clients;
public TenantCommunicationClientComposite(ITenantContext tenantContext,
Dictionary<string, ICommunicationClient> clients) {
this.tenantContext = tenantContext;
this.clients = clients;
}
object ICommunicationClient.ClientMethod(object parameter) =>
this.clients[this.tenantContext.CurrentTenantName].ClientMethod(parameter);
}
You can register this class as follows:
var dictionary = new Dictionary<string, ICommunicationClient>();
foreach (var supportedTenant in supportedTenants) {
dictionary.Add(supportedTenant, new CommunicationClient(
new Uri(configuration.AppSettings["communication_api." + supportedTenant]),
new TenantClientConfiguration(supportedTenant)));
}
container.RegisterSingleton<ICommunicationClient>(
new TenantCommunicationClientComposite(
new AspNetTenantContext(),
dictionary));
Here the ITenantContext is an abstraction that allows you to get the current tenant on who's behalf the current request is running. The AspNetTenantContext is an implementation that allows you to retrieve the current tenant in an ASP.NET application. You probably already have some code to detect the current tenant; you might need to move that code to such AspNetTenantContext class.
I have a web app that contains an activity log for actions the users take. There are multiple types of activities that can be logged.
Here's an example:
public static class NewAccountActivity() {
public static Write(string username) {
//... do stuff to enter a new account activity into the database ...
}
}
public static class NewPostActivity() {
public static Write(string username, long postId, string postTitle) {
//... do stuff to enter a new post activity entry into the database ...
}
}
And then go on to create a new class for every single type of activity to log. Each activity has a .Write() method, with a unique signature for each one (as shown in the code example above)
And then in my web app (asp.net mvc based) I use them like this:
public ActionResult NewAccount(Account account) {
if (Model.IsValid(account)) {
//... do new account stuff ...
NewAccountActivity.Write(account.UserName);
//... redirect to action, or show view ...
}
}
public ActionResult NewPost(Post post) {
if (Model.IsValid(post)) {
//... do new post stuff ...
NewPostActivity.Write(post.UserName, post.postId, post.Title);
//... redirect to action, or show view ...
}
}
Is this a bad idea? Is there a better way? Should these be a bunch of methods jammed into one class?
I started doing this because of an answer to a different question I had on SO.
This is my suggestion.
First of all, no static class should represent an activity. The Logger class can be static, or accessible through a DI container.
Create an interface for an activity, namely IActivity that has a single Write or Log method. For each activity where the processing is bigger than a single line of code, create a class that implements the IActivity interface.
Now for all other simple activity log, create a default activity that accept a function lambda.
Example, in this code, I assume that each activity builds a string and return it through the Log function:
public class NewAccountActivity : IActivity
{
private string userName;
public NewAccountActivity(string userName)
{
this.userName = userName;
}
public string Log()
{
return this.UserName;
}
}
public class ActivityEntry : IActivity
{
private Func<string> action;
public ActivityEntry(Func<string> action)
{
this.action = action;
}
public string Log()
{
return this.action();
}
}
Now in your static Logger class, create two functions:
public static class Logger
{
public static void Write(IActivity activity)
{
// Ask activity for its data and write it down to a log file
WriteToFile(activity.Log());
}
public static void Write(Func<string> action)
{
Write(new ActivityEntry(action));
}
}
Then in your code, call your logger class like this:
Logger.Write(new NewAccountActivity(currentUserName));
or if you need to log something else that is simple:
Logger.Write(() => "Hello world");
This last call will create a new instance of ActivityEntry that will log "Hello World".
How about a logger class that takes an enum as an argument so that it knows what type of "activity" it is logging and how to deal with it?