1

I am working on a very old, but very large and very active ASP.NET webforms site, that uses a custom Session State provider that relies on JSON.Net.

One side effect of this is that objects that are based on plain, non-generic IEnumerable can be put in Session, but not retrieved from it. This is a JSON.Net limitation (an exception will be thrown if you try.)

Stripped of its details, my situation is this: I need to stash an object in Session, of a third-party-provided, sealed class, for which I don't have the source code, that's based on IEnumerable. (We'll call it VendorClassA.)

And: I need to be able to get it out again.

And that's what doesn't work.

I have tried mapping an instance of VendorClassA to something else, stashing that in Session, and then converting it back. That works quite well.

But it turns out that there's one place -- within the third-party, inaccessible code -- where an instance of VendorClassA is retrieved from Session, and if it can't be retrieved, or if the retrieved object can't be cast to VendorClassA, a fatal exception is thrown.

VendorClassA value = (VendorClassA) HttpContext.Current.Session["key"];

I can't change that code (third-party, no source code, etc.)

And I can't modify the code that does the actual JSON.Net serialization, to change which methods are invoked, or how, because that's deep in the custom session state provider. Which I have no access to, both programmatically and organizationally.

So, my question:

Is there any way I can affect how JSON.Net handles this specific class's serialization, given that I can't change any of the following:

  • That the object I put into Session State needs to be an instance of VendorClassA, or at least castable to it, because code I can't change will try to cast it to VendorClassA.
  • The attributes on VendorClassA
  • That it's based on plain, non-generic IEnumerable.
  • That VendorClassA is sealed
  • How the JSON.Net serialization routines are called and what parameters or overloads they use.

Perhaps there's some way to introduce a custom contract for VendorClassA, that would be globally applicable, but which could be introduced from a distance?

Is there a better way?

Ann L.
  • 13,760
  • 5
  • 35
  • 66
  • How that object is retrieved from the session? You say "That the object needs to be an instance of VendorClassA, or at least castable to it", but don't you specify exactly what type you (that third party library) want? That is - JSON.NET should know to which type to deserialize to. – Evk Sep 30 '21 at 13:57
  • @Evk What I meant by that line: there's a place in the 3rd party code that looks like this: `VendorClassA value = (VendorClassA) HttpContext.Current.Session["key"];` – Ann L. Sep 30 '21 at 14:32
  • So, whatever I get out of session has to be something that's castable to `VendorClassA`. If I put in a custom object (as I describe doing in paragraph 6), this line of code will fail. – Ann L. Sep 30 '21 at 14:33
  • I don't know exactly how the Session State provider uses JSON.Net, but it seems to be able to serialize/deserialize most objects, so presumably the original type is being passed to the serializer, somewhere deep in the Session provider code. – Ann L. Sep 30 '21 at 14:35
  • 1
    Try using `JsonConvert.DefaultSettings` to set a custom converter for `VendorClassA`. See: [Set default global json serializer settings](https://stackoverflow.com/a/21815974/3744182). This will work if your 3rd party code uses `JsonConvert.DeserializeObject()` or `JsonSerializer.CreateDefault()` but will not work if your third party uses `JsonSerializer.Create()` or `new JsonSerializer()` directly. Since there's no [mcve] we have no way of knowing which the 3rd party library uses, but you can test it yourself and you may get lucky. – dbc Sep 30 '21 at 14:52
  • 1
    Assuming `JsonConvert.DefaultSettings` works at all, your options are to inject a custom converter or custom contract resolver for `VendorClassA`. Probably a custom converter is the way to go, see [JSON.net ContractResolver vs. JsonConverter](https://stackoverflow.com/q/41088492/3744182) for a discussion of when to use each. – dbc Sep 30 '21 at 15:00
  • @dbc Thank you! I'll give that a try! – Ann L. Sep 30 '21 at 15:08
  • Did `JsonConvert.DefaultSettings` work? If not, might you please [edit] your question to share the full `ToString()` output of the exception including the exception type, message, traceback and inner exception(s) if any? – dbc Oct 01 '21 at 18:16
  • 1
    Hi, @dbc. What's happened is that I've abandoned this project. There were other problems with it that would have made any working solution brittle and full of code smells. (See [C#: Writing an explicit cast operator for an internal class in another .NET assembly](https://stackoverflow.com/questions/69394587/c-writing-an-explicit-cast-operator-for-an-internal-class-in-another-net-asse), which is a doozy. ) – Ann L. Oct 02 '21 at 15:04
  • @dbc I have started a new one that has the same functionality goals, but is all custom code, and therefore doesn't need to interact with `VendorClassA`, or with vendor code at all. – Ann L. Oct 02 '21 at 15:05
  • @dbc But, since yours was the approach I was going to try, and you did answer the question, if you post your suggestion as an answer, I'll mark it as accepted. – Ann L. Oct 02 '21 at 15:06
  • Rather than answering, I went ahead and marked it as a duplicate. – dbc Oct 02 '21 at 16:38

0 Answers0