Explicitly persist states in Workflow 4.0 rather than everything - c#

I have ran into an issue with my SQL instance store attached to a WorkflowApplication that is running. When I exit my application I'm calling an Unload() on the WF app to persist it. I didn't think about it during design time, but it does makes sense, it's persisting an arg that was passed in to the WorkflowApplication constructor when instanced.
When the application runs, everything in the workflow works as expected. When I call Unload() I get an unhandled exception that states that the arg is not serializable and needs [DataContractAttribute].
What's passed into the workflow is my applications custom logger object that I wrote so that the WF can log to disk in a uniform way that I prefer. How do I prevent the workflow app from persisting this one argument and persist everything else?
I'm sure something can be done with extensions but I'm having a hard time finding info on them or finding persistence examples for my scenario.

You can decorate the variable to not be serialised, with a [NonSerialized] attribute.
That should do the trick, it worked for me in a WF3.5 app. See http://msdn.microsoft.com/en-us/library/ms973893.aspx, heading "Selective Serialization"

Related

How to best deploy Sentry in cross-assembly environment?

So we built this library/framework thing full of code related to business processes and common elements that are shared across multiple applications (C#, .Net 4.7.1,WPF, MVVM). Our Logging stuff is all set up through this framework so naturally it felt like the best place for Sentry. All the references in our individual applications are manually pointed to the dlls the folder where our shared library thingy installs itself. So far so good.
When we set up Sentry initially everything seemed to work great. We do some updates and errors seem to be going way down. That's cause we are awesome and Sentry helped us be more awesome, right? Nope! Well I mean kind of.
The scope is being disposed of so we are no longer getting Unhandled exceptions. We didn't notice at first because we are still getting sentry logs when we are handling errors through our Logging.Log() method. This logging method calls SentrySdk.Init() which I suspect is disposing the client in the executing assembly.
We also started using Sentry for some simple Usage tracking by spinning up a separate project in Sentry called Usage-Tracker and passing a simple "DoThingApplication has been launched" with an ApplicationName.UsageTracker Enum as a parameter to our Logging method.
Question: What is a good way to handle this where my setup can have a Sentry instance that wraps my using(sentryClientStuff){ ComposeObjects(); } and still have my logging method look for the existing client and use it if it exists?
Caveats:
I believe before any of this happens we still need to make a call to send a Sentry log to our UsageTracker.
I would like to pass in as few options as possible if I'm setting up the Sentry Client/Scope in our shared library. Maybe Release and Environment. Maybe check tags for Fingerprint and set it in the Log method.
I'm open to new approaches to any of this.
Some related thoughts
Maybe there is a better way to handle references that could solve both this and some other pains of when they have become mismatched between client and shared framework/library thing
Maybe the answer can be found through adding some Unit Tests but I could use a Sentry specific example or a nudge there because I don't know a muc about that.
Maybe there is a way to use my shared library to return a Sentry Client or Scope that I could use in my client assembly that would not be so fragile and the library could somehow also use it.
Maybe there is a better solution I can't conceive because I'm just kind of an OK programmer and it escapes me. I'm open to any advice/correction/ridicule.
Maybe there is a smarter way to handle "Usage-Tracker" type signals in Sentry
Really I want a cross-assembly singleton kind of thing in practice.
There are really many things going on here. Also without looking at any code it's hard to picture how things are laid out. There's a better chance you can get the answer your are looking for if you share some (dummy even) example of the structure of your project.
I'll try to break it down and address what I can anyway:
With regards to:
Usage-Tracker:
You can create a new client and bind to a scope. That way any use of the SentrySdk static class (which I assume your Logger.Log routes to) will pick up.
In other words, call SentrySdk.Init as you currently do, with the options that are shared across any application using your shared library, and after that create a client using the DSN of your Usage-Tracker project in sentry. Push a scope, bind the client and you can use SentrySdk with it.
There's an example in the GitHub repo of the SDK:
using (SentrySdk.PushScope())
{
SentrySdk.AddBreadcrumb(request.Path, "request-path");
// Change the SentryClient in case the request is to the admin part:
if (request.Path.StartsWith("/admin"))
{
// Within this scope, the _adminClient will be used instead of whatever
// client was defined before this point:
SentrySdk.BindClient(_adminClient);
}
SentrySdk.CaptureException(new Exception("Error at the admin section"));
// Else it uses the default client
_middleware?.Invoke(request);
} // Scope is disposed.
The SDK only has to be initialized once but you can always create a new client with new SentryClient, push a new scope (SentrySdk.PushScope()) and bind it to that new scope (SentrySdk.BindClient). Once you pop the scope the client is no longer accessdible via SentrySdk.CaptureException or any other method on the static class SentrySdk.
You can also use the client directly, without binding it to the scope at all.
using (var c = new SentryClient(new SentryOptions { Dsn = new Dsn("...") })) {
c.CaptureMessage("hello world!");
}
The using block is there to make sure the background thread flushes the event.
Central place to initialize the SDK:
There will be configuration which you want to have fixed in your shared framework/library but surely each application (composition root) will have its own setting. Release is auto-discovered.
From docs.sentry.io:
The SDK will firstly look at the entry assembly’s AssemblyInformationalVersionAttribute, which accepts a string as value and is often used to set a GIT commit hash.
If that returns null, it’ll look at the default AssemblyVersionAttribute which accepts the numeric version number.
If you patch your assemblies in your build server, the correct Release should be reported automatically. If not, you could define it per application by taking a delegate that passes the SentryOptions as argument.
Something like:
Framework code:
public class MyLogging
{
void Init(Action<SentryOptions> configuration)
{
var o = new SentryOptions();
// Add things that should run for all users of this library:
o.AddInAppExclude("SomePrefixTrueForAllApplications");
o.AddEventProcessor(new GeneralEventProessor());
// Give the application a chance to reconfigure anything it needs:
configuration?.Invoke(o);
}
}
App code:
void Main()
{
MyLogging.Init(o => o.Environment = "my env");
}
The scope is being disposed of so we are no longer getting Unhandled exceptions."
Not sure I understand what's going on here. Pushing and popping (disposing) scopes don't affect the ability of the SDK to capture unhandled exceptions. Could you please share a repro?
This logging method calls SentrySdk.Init() which I suspect is disposing the client in the executing assembly.:
Unless you create a client "by hand" with new SentryClient, there's only 1 client in the running process. Please note I said running process and not assembly. Instances are not held within an assembly. The assembly only contains the code that can be executed. If you call SentrySdk.CaptureException it will dispatch the call to the SentryClient bound to the current scope. If you didn't PushScope, there's always an implicit scope, the root scope. In this case it's all transparent enough you shouldn't care there's a scope in there. You also can't dispose of that scope since you never got a handle to do so (you didn't call PushScope so you didn't get what it returns to call Dispose on).
All the references in our individual applications are manually pointed to the dlls the folder where our shared library thingy installs itself.:
One thing to consider, depending on your environment is to distribute packages via NuGet. I'm unsure whether you expect to use these libraries in non .NET Framework applications (like .NET Core). But considering .NET Core 3.0 is bringing Windows Desktop framework support like WPF and WinForm, it's possible that eventually you will. If that's the case, consider targeting .NET Standard instead of .NET Framework for your code libraries.

NHibernate - Creating a proxy instance failed (on IIS8 but ok with dev server)

I have to work on already developed solution which is using NHibernate (v1.2.1.4000) with SQL Server 2008.
The application is using .NET Framework 2.0 due to Membership authentication and other stuffs.
This is working in Visual Studio - I can debug it, run in. But failed when deployed in IIS (v8.0)
Exception is:
Duplicate type name within an assembly.
HibernateException: Creating a proxy instance failed.
And it occurred whenever database is fetched to get some models.
I have googled on this issue and have some suggestion to use nhiberante (v3.3.x).
But the lots of interfaces and method parameters are different in v3. so it is breaking implementaion of the source code.
Several questions regarding this exist on stackoverflow but no luck yet
Maybe you have a concurrency trouble, something like singleton initialization failing to ensure uniqueness of its initialization, occurring only under load.
Especially check your session factory. Put logs when building it, check it is not built multiple times. Try triggering your singleton initializations from Application_Start if they are not already triggered from there.
Avoid singleton lazy initializations unless they are really heavy and not needed for most of you application HTTP requests. In such case, make sure their logic is thread safe and avoid running concurrent initializations (something like LazyThreadSafetyMode ExecutionAndPublication instead of PublicationOnly: it requires stricter locking but must be done that way for building the ISessionFactory, if it is done through lazy initialization.)

HttpContext.Cache Add vs Insert and Session

Basically I know what the difference is. Also, I do know (as you all) there is a lot of resources discussing the issue (e.g. here).
But today, I heard an strange and weird idea which says Add method, adds the object to application-scope cache, while the Insert method will adds the object to the session-scope cache!!!
I mean HttpContext.Current.Cache.Add will add object to a shared memory which is accessible for all users/threads/sessions/requests/etc.
But HttpContext.Current.Cache.Insert will add the object to a session-dependent cache (which actually would be the session itself. right? :D)!!!
It's the first time I'm hearing such a thing. I did search the msdn and technet.microsoft.com. I also did decompile the Cache class (via dear ReSharper) and read the entire code (and it's dependencies). But nothing came out which make a dependency between Cache and Session.
I'm just asking. Is there any relationship between Cache and Session?
Note: The app is running on a web garden in a Win 2012 R2 machine with IIS 8.5.
There are separate and in a different scope to each other.
As far as I can see, both Methods are applicable to the Cache object and calling Add will not have any interaction with the Session object

Determine if SqlDependency.Start(connectionstring) has been called in current project?

Our applications use a lot of shared components. Some of them have no need for caching, for example, Windows Services which process unmailed emails. You'd never cache that result set...
Problem is, since our shared data layer has been modified to use SqlCacheDependency, our services which don't start SqlDependency fail on database calls where the data layer requests a SqlCacheDependency object.
Which leads to the question - is there a way for our data classes to test to see if the broker service is listening (ie: has SqlDependency.Start(connectionString) been called)?
The SqlDependency object itself has no Enabled or similar property. Is there any way short of forcing the calling app to tell the data layer that SqlCaching is in use for the data layer to determine the state?
Pretty much the answer is no. We ended up adding a config variable that if false or not present, causes the request to use SqlCacheDependency to be skipped.
SELECT * FROM sys.service_queues WHERE name LIKE 'SqlQueryNotificationService-%'
returns a 'SqlQueryNotificationService-[some guid]'
And if you look deep in the Non-public members of the SqlDependency _serverUserHash while debugging in the IDE, you'll find a collection that contains that same entry. If Microsoft would be so kind as to expose that, then yes.
In my case I have a class library which is used by some web applications. So I have no App.config. I also use the SqlCacheDependency in a static event. So I'm using a static boolean like:
if (!isCachingEnabled)
isCachingEnabled = SqlDependency.Start(builder.ProviderConnectionString);
So far is working but I'm open to suggestions when using Class Libraries.

Need help avoiding the use of a Singleton

I'm not a hater of singletons, but I know they get abused and for that reason I want to learn to avoid using them when not needed.
I'm developing an application to be cross platform (Windows XP/Vista/7, Windows Mobile 6.x, Windows CE5, Windows CE6). As part of the process I am re-factoring out code into separate projects, to reduce code duplication, and hence a chance to fix the mistakes of the inital system.
One such part of the application that is being made separate is quite simple, its a profile manager. This project is responsible for storing Profiles. It has a Profile class that contains some configuration data that is used by all parts of the application. It has a ProfileManager class which contains Profiles. The ProfileManager will read/save Profiles as separate XML files on the harddrive, and allow the application to retrieve and set the "active" Profile. Simple.
On the first internal build, the GUI was the anti-pattern SmartGUI. It was a WinForms implementation without MVC/MVP done because we wanted it working sooner rather than being well engineered. This lead to ProfileManager being a singleton. This was so from anywhere in the application, the GUI could access the active Profile.
This meant I could just go ProfileManager.Instance.ActiveProfile to retrieve the configuration for different parts of the system as needed. Each GUI could also make changes to the profile, so each GUI had a save button, so they all had access to ProfileManager.Instance.SaveActiveProfile() method as well.
I see nothing wrong in using the singleton here, and because I see nothing wrong in it yet know singletons aren't ideal. Is there a better way this should be handled? Should an instance of ProfileManager be passed into every Controller/Presenter? When the ProfileManager is created, should other core components be made and register to events when profiles are changed. The example is quite simple, and probably a common feature in many systems so think this is a great place to learn how to avoid singletons.
P.s. I'm having to build the application against Compact Framework 3.5, which does limit alot of the normal .Net Framework classes which can be used.
One of the reasons singletons are maligned is that they often act as a container for global, shared, and sometimes mutable, state. Singletons are a great abstraction when your application really does need access to global, shared state: your mobile app that needs to access the microphone or audio playback needs to coordinate this, as there's only one set of speakers, for instance.
In the case of your application, you have a single, "active" profile, that different parts of the application need to be able to modify. I think you need to decide whether or not the user's profile truly fits into this abstraction. Given that the manifestation of a profile is a single XML file on disk, I think it's fine to have as a singleton.
I do think you should either use dependency injection or a factory pattern to get a hold of a profile manager, though. You only need to write a unit test for a class that requires the use of a profile to understand the need for this; you want to be able to pass in a programatically created profile at runtime, otherwise your code will have a tightly coupled dependency to some XML file on disk somewhere.
One thing to consider is to have an interface for your ProfileManager, and pass an instance of that to the constructor of each view (or anything) that uses it. This way, you can easily have a singleton, or an instance per thread / user / etc, or have an implementation that goes to a database / web service / etc.
Another option would be to have all the things that use the ProfileManager call a factory instead of accessing it directly. Then that factory could return an instance, again it could be a singleton or not (go to database or file or web service, etc, etc) and most of your code doesn't need to know.
Doesn't answer your direct question, but it does make the impact of a change in the future close to zero.
"Singletons" are really only bad if they're essentially used to replace "global" variables. In this case, and if that's what it's being used for, it's not necessarily Singleton anyway.
In the case you describe, it's fine, and in fact ideal so that your application can be sure that the Profile Manager is available to everyone that needs it, and that no other part of the application can instantiate an extra one that will conflict with the existing one. This reduces ugly extra parameters/fields everywhere too, where you're attempting to pass around the one instance, and then maintaining extra unnecessary references to it. As long as it's forced into one and only one instantiation, I see nothing wrong with it.
Singleton was designed to avoid multiple instantiations and single point of "entry". If that's what you want, then that's the way to go. Just make sure it's well documented.

Categories

Resources