static class configuration for service fabric actors - c#

Service fabric actors are used to access database and all the methods suppose to use Dapper as ORM tool.
One thing I found out as the best way to solve current problem is using something called SqlMapper in Dapper. With that, you can define general behavior in handling certain data types, for example:
SqlMapper.AddTypeHandler(new DateTimeHandler());
public class DateTimeHandler : SqlMapper.TypeHandler<DateTime>
{
public override void SetValue(IDbDataParameter parameter, DateTime dateTime)
{
parameter.Value = dateTime.ValidateDateTime();
}
public override DateTime Parse(object value)
{
return ((DateTime)value).ValidateDateTime();
}
}
As you declare static method above (AddTypeHandler) with custom handler such as DateTimeHandler, the mapping done using Dapper framework will make sure any dateTime type goes through above handler correctly.
I would like to see this happening as each Actor communicates to database via Dapper.
I haven't seen it happening yet declaring above static method in attempts with several different places such as Actor constructor() or the main method such as below:
private static void Main()
{
try
{
// This line registers an Actor Service to host your actor class with the Service Fabric runtime.
// The contents of your ServiceManifest.xml and ApplicationManifest.xml files
// are automatically populated when you build this project.
// For more information, see https://aka.ms/servicefabricactorsplatform
ActorRuntime.RegisterActorAsync<SqlRepositoryActor>(
(context, actorType) => new ActorService(context, actorType)).GetAwaiter().GetResult();
// This doesn't seem like a right place as I don't see the handler being called when Actor uses dapper mapping methods.
SqlMapper.AddTypeHandler(new DateTimeHandler());
Thread.Sleep(Timeout.Infinite);
}
catch (Exception e)
{
ActorEventSource.Current.ActorHostInitializationFailed(e.ToString());
throw;
}
}

I usually don't want to answer my own question, but here is what I found out so far.
First of all, maybe I need to change the title of this question if I want the actual solution solving the issue to be more relevant to the title itself. However since the titled question is answered with this post, I will keep it as is.
To give the short answer, static class configuration can be done with all the places I mentioned above such as Actor constructor, OnActivateAsync(), etc, as static class is still shared across different threads (Actors are all single independent threads) within the AppDomain (And actors are running within the AppDomain. Please correct me if I am wrong.)
What actually caused the above issue was because the mapping definition using Dapper was declared as dynamic; shown below:
return sqlConnection.Query<dynamic>(some_sql_script, new { objInstance }).FirstOrDefault();
Once you change the expected return type T to strong type which contains the typeHandler type, then Dapper invoked the typeHandler correctly:
return sqlConnection.Query<StrongType>(some_sql_script, new { objInstance }).FirstOrDefault();

Related

Preventing multiple switch statements

I'm currently writing a custom logging method for my Web API where users can purchase items. This log method will log all the steps the users takes while following a purchase process so support can later track the steps. There are multiple steps like:
Creating a order
Updating a order
Purchasing a item
Receiving status
etc..
This method will return one 'Event' object where all the necessary log information is combined, for example the LogLevel, Message, UserId and more, and write this to a database.
Before i can reach this point, i have to create the very useful log message. The message is based on these two enums (explanation is a bit simplified):
ActionName - At which step in my process is this log event called
ActionOrigin - Is the recorded log event from my front end or backend system...
It is also based on a object where the necessary log values, like order id for example, are provided.
The log class where the log event method is defined is a scoped injected class so i can log events every where critical in my code.
The first thing that came into my mind was creating a switch statement and create the messages based on the correct case. But this would combine 2 switch statements and quickly started to look like a mess.
I did some research and found the strategy pattern. I'm not completely sure if this can help me? Are there any other ideas or examples?
Whenever you are working on an object model and find yourself writing a ton of switch statements, it usually means you've put the class-specific logic in the wrong place. You should put it with the class itself, not the class that consumes it.
To put it another way, your logger should not know how to log each and every type of event. That would be a maintenance nightmare. Instead, it should know how to log a common object (e.g. a string), and each event should itself know how to create that common object, via a common method that the logger knows about. That is the only thing it needs to know.
Here is a simple example. In this case, the logger accepts any type of LoggableEvent and calls its Serialize() method to figure out how it gets added to the common log. The event itself is responsible for knowing how to serialize itself.
abstract class LoggableEventBase
{
public string ActionName { get; }
public string ActionOrigin { get; }
public LoggableEventBase(string actionName, string actionOrigin)
{
ActionName = actionName;
ActionOrigin = actionOrigin;
}
public virtual string Serialize()
{
return string.Format("{0} {1}", ActionName, ActionOrigin);
}
}
class CreateOrderEvent : LoggableEventBase
{
protected readonly List<Item> _items;
protected readonly int _orderId;
public CreateOrderEvent(string origin, int orderID, List<Item> items) : base("CreateOrder", origin)
{
_orderId = orderID;
_items = items;
}
public override string Serialize()
{
return base.Serialize() + string.Format(" {0} {1}", _orderId, string.Join(",", _items.Select(item => item.SKU)));
}
}
Now the actual logging logic is rather simple-- no switch statements or anything else that needs to know what the event is:
class Logger : ILogger
{
public void Log(LoggableEventBase eventToLog)
{
Write(eventToLog.Serialize());
}
protected virtual void Write(string message)
{
//Write the message to a log file
}
}
To add additional event types, you just need to define the new class (and override Serialize()). You never have to go back and modify the Logger class. This is more consistent with the Open-Closed Principle than your existing solution.
This is a design pattern question. You might want to read on different patterns used for the language/framework you are using. It seems like you are trying to avoid writing your logs in line. One way of doing it would be to define the format for your different messages in a constant and use string interpolation (or simple concatenation) to build the message with a log() method.
Example (I'll do my best to write proper C#, please edit any mistakes or inadequacies):
class Logger {
// If you want personalized messages for different actions or origins, define their template constants and create different methods for building them.
public const string ORDER_PROGRESS_MSG_TMPL = "Action:{0}, Origin:{1}, OrderId:{3}";
void log_order_progress(string actionName, sting actionOrigin, string orderId){
Console.WriteLine(
ORDER_PROGRESS_MSG_TMPL, actionName, actionOrigin, orderId
);
}
}
Order
class Order {
...
void create(int orederId){
Logger.log_order_progress(ActionEnum.CREATING, OriginEnum.BACK_END, orderId)
// Do some stuff here to create order
Logger.log_order_progress(ActionEnum.UPDATING, OriginEnum.BACK_END, orderId)
// etc
}
}
This is a way of doing it, you could modularize it more by having templates in their own class. Also you could create (or better: use an existing logging framework) to differentiate level of logging (debug, info, error) as #Sandeep Sharma described.
You can create multiple methods in your Logger class, each for specific scenario.
The methods can be :
info() = for logging some information.
debug() = for debugging.
error() = for logging an error event.
Let's say you want to log an event of purchasing an item , and when user does buy action, you can pass information to the logger.info() method.
If you encounter an error, or a certain action or condition was not fulfilled , you can pass data to the method error() , which will log error in your case.
For messages :
1. Action Name - You can pass the method name or route path that was called by action of an user.
2. Action Origin - Provide details like user name , full path , action type etc.
You can also maintain fields like 'timestamp' and some 'unique-identifier' for better logging of events.

Reference object in two classes C#

Let's go straight to my probably fairly simple problem.
I have a LoginService class in my Services folder which makes a connection with the server. I have another UserModel where I want to receive information from the server. In order not to login again (which would be stupid), I need to maintain the client reference in both files having the same value. In other words, I need to be able to access the same object from a different class (make another reference).
I have tried and tried and searched but I am missing something.
A fairly similar post that I found that still didn't solve mine is this.
The code in my LoginService:
namespace App_Name.Services
{
class LoginService
{
public static Class_Name client;
public async Task MakeConnectionAsync(string userToken)
{
client = new Class_Name();
PasswordVault vault = new PasswordVault();
await client.LoginAsync(TokenType.User, userToken);
await client.StartAsync();
}
So now I want to get the user avatar on my UserModel.cs:
namespace App_Name.Models
{
class UserModel
{
public string GetAvatar()
{
return LoginService.client.CurrentUser.GetAvatarUrl();
}
But it always gives an exception because it tries but there is no connection.
I am sure that it was Connected because in order to load the UserModel it has to be a successful connection.
Any ideas ?
When you call directly the client.CurrentUser.GetAvatarUrl() method, its not determined by the LoginService class. You should be create the Login class before the usage. Also you are using async tasks on your LoginService class, you must confirm that already create user by your UserModel class.
For best practice you can create instance with your constructor like this.
static class LoginService
{
public static Class_Name client;
static LoginService()
{
client = new Class_Name();
}
If you want to go with static (which I not prefer for service level) not use static for like this purpose of usage.
Firstly you should be check dependency injection concepts; i suggest unity and structuremap containers. You can create your consume services by your classes without any object null ref. exception. Dependency injection decrease on coupling and null reference exception.
Ehmmm, for anyone that can use this as a reference, my code above is just fine.
The problem was with the connection API not returning the status immediately. A delay of 2 seconds solved my problem. Thanks everyone for their help.

Structuremap - Override registration

Is it possible to register an interface in a registry, then "re-register" it to override the first registration?
I.E.:
For<ISomeInterface>().Use<SomeClass>();
For<ISomeInterface>().Use<SomeClassExtension>();
What I want here on runtime is that my object factory returns SomeClassExtension when I ask for ISomeInterface.
Thanks in advance!
Good news, I found out that yes. It all depends on the order that the registry rules are added to the object factory container. So if you are using multiple registry classes as I was doing, you need to find a way to give a priority to add them to the container.
In other words, instead of using the .LookForRegistries() which gets all the Registry classes in the wrong order, try to find all the Registry files, set them in the order you want and add them manually to the object factory container:
ObjectFactory.Container.Configure(x => x.AddRegistry(registry));
That way, you have full control on what rules you want.
Hope it helps :)
I just wanted to add my solution to the problem when I needed to override some parts of a registry in my SpecFlow test.
I did find this thread pretty early in my search, but it didnĀ“t really help me find the solution, so I hope it will help you.
My problem was that the "DataContext" in "StoreRegistry" (used by the application) use the "HybridHttpOrThreadLocalScoped" and I needed it to be "Transient" in my tests.
The code looked like this:
[Binding]
public class MySpecFlowContext
{
...
[BeforeFeature]
private static void InitializeObjectFactories()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry<StoreRegistry>();
x.AddRegistry<CommonRegistry>();
});
}
}
To override the scope setting you will need to explicitly set it in the registration.
And the override needs to be below what is overridden
The working code looks like this:
[Binding]
public class MySpecFlowContext
{
...
[BeforeFeature]
private static void InitializeObjectFactories()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry<StoreRegistry>();
x.AddRegistry<CommonRegistry>();
x.AddRegistry<RegistryOverrideForTest>();
});
}
class RegistryOverrideForTest : Registry
{
public RegistryOverrideForTest()
{
//NOTE: type of scope is needed when overriding the registered classes/interfaces, when leaving it empty the scope will be what was registered originally, f ex "HybridHttpOrThreadLocalScoped" in my case.
For<DataContext>()
.Transient()
.Use<DataContext>()
.Ctor<string>("connection").Is(ConnectionBuilder.GetConnectionString());
}
}
}

Why am I getting "Row Not Found Or Changed" Error Here?

I've googled around the "Row Not Found or Changed" error for some time, and I'm just unable to see how the error is being caused in my application.
I have a facade class, called DataAccess, which wraps multiple repositories, and gets passed around my application. Every controller has a dependency upon DataAccess, so I've hooked it up to unity to pass out as required.
Data Access looks roughly like this, in truncated/abstracted form:
public class DataAccess : IDataAccess
{
private MyDataContext DataContext = new MyDataContext();
public Repository1 Repo1 = new Repository1();
public Repository2 Repo2 = new Repository2();
public DataAccess()
{
Repo1.DataContext = DataContext;
Repo2.DataContext = DataContext;
}
}
Then each controller has a dependency upon IDataAccess like so:
public class MyControllerBase
{
[Dependency]
IDataAccess DataAccess { get; set; }
}
Unity hands these out according to what appears to be normal configuration, registering types in Global.asax, hooking controllers up to a factory, resolving with unity. Furthermore, I've registered it with a PerThreadLifetimeManager(), which I am unsure whether is correct.
For the most part this works great - however the problem can be reproduced by:
Go to Edit action and post an edit (redirects to Index)
Go back into the Edit action and attempt to post another edit, OR, go into Delete action and attempt to post a Delete on the same item
This throws the "Row Not Found or Changed" error. Each action (Edit and Delete) calls SubmitChanges() on the DataContext. So I'm not quite sure what's going on here. If anyone has any ideas they would be extremely well received.
Cheers,
Tim.
I suspect the per-thread lifetime is not appropriate here - ASP.NET reuses threads across requests, and that would result in reusing your old contexts across multiple requests, possibly leaving them in odd states.
You have two choices:
If you only call container.resolve on the controller, then you could use the built-in PerResolveLifetimeManager instead. This would give you a single DataAccess object per controller resolve.
You could grab one of the many PerRequestLifetimeManager implementations and get a new DataAccess object per HttpRequest.
Either way will, I suspect, get you out of the issues you've got currently.

How to pass an object to a web service?

I already searched a lot in Google.
I created a EntityClass on client side, and then I added the library reference of this class on Web Service side. But when I want to call the method, it shows this error:
Error 2 Argument 1: cannot convert
from
'Services_Library.UserService.UserServiceSoapClient'
to
'Services_Library.UserService.UserEntity'
here is the code, this method is called from a User Interface:
public UserEntity test(UserEntity userEntityx)
{
UserService.UserServiceSoapClient userService = new UserService.UserServiceSoapClient();
userService.testUserAsync(new UserEntity());
}
I think we can do this without explicit serialization, right? If so, I prefer this way.
I think the problem is when you actually call the service, you're passing in the serviceReference and not the object that the call accepts. I think it should look something like:
public UserEntity test(UserEntity userEntityX)
{
var userService = new UserService.UserServiceSoapClient();
return userService.testUser(userEntityX);
}
No explicit serialization needed.
Also, keep in mind that if you're calling the Async version of the method you're code is going to become more complicated. I used the synchronous version in my example.

Categories

Resources