Code Monkey home page Code Monkey logo

Comments (7)

s-leonard avatar s-leonard commented on September 28, 2024

Any news on this?

This would be very handy. We are are adding simple objects (that we cannot change as from another project) into temp data and getting the error: Type is not marked as Serializable

Json.Net's JsonConvert.SerializeObject() method would serialise these without the need to add the serializable attribute.

This issue has currently stopped us being able to use the cookieTempData

from cookietempdata.

brockallen avatar brockallen commented on September 28, 2024

Feel free to make a PR with this enhancement.

from cookietempdata.

luisgoncalves avatar luisgoncalves commented on September 28, 2024

I've also run into the Serializable requirement and the size issue is also significant. I've done some tests to different types of serialization options: https://github.com/luisgoncalves/CookieTempData/tree/serialization-tests.

Some quick results for that test data (10000 iterations):

  • BinarySerializeWithCompression (currently used): Individual size: 577, Total time: 00:00:01.2223728
  • BsonSerializeWithCompression (using JSON.NET): Individual size: 313, Total time: 00:00:00.8249299
  • BsonSerializeWithoutCompression (using JSON.NET): Individual size: 513, Total time: 00:00:00.1688722
  • JsonSerializeWithCompression (JavascriptSerializer): Individual size: 170, Total time: 00:00:00.6050056
  • JsonSerializeWithoutCompression (JavascriptSerializer): Individual size: 228, Total time: 00:00:00.1703267

The code with JavascriptSerializer is already on the project's source; just needs a tweak.

Using JSON.NET is no better than the JavascriptSerializer and the latter avoids the extra dependency. In addition, it doesn't required the [Serializable] attribute. Finally, compression could probably be removed since the difference is not very big, with the corresponding small performance improvement.

The sample data on the tests is rather basic in terms of types, but I guess real uses cases aren't much different.

What do you think? The changes are minimal.

from cookietempdata.

brockallen avatar brockallen commented on September 28, 2024

Feel free to submit a PR if your numbers support smaller size and better perf.

from cookietempdata.

luisgoncalves avatar luisgoncalves commented on September 28, 2024

Well, testing deserialization shows that JavaScriptSerializer may not work. It doesn't seem to have a way to write type information and since we're deserializing into a "object" dictionary, it fails on later casts.

I'll try to submit a PR based on JSON.NET.

from cookietempdata.

brockallen avatar brockallen commented on September 28, 2024

I'll reopen if/when PR is submitted.

from cookietempdata.

luisgoncalves avatar luisgoncalves commented on September 28, 2024

In case someone wants to do the PR that changes the provider to JSON.NET, here's the code:

/// <summary>
    /// A provider for TempData that stores data on cookies. 
    /// Based on https://github.com/brockallen/CookieTempData
    /// Changes:
    ///     - Use Json.Net BsonSerializer
    ///     - Do not compress
    /// </summary>
    public class CookieTempDataProvider : ITempDataProvider
    {
        const string AnonymousCookieValuePrefix = "_";
        const string AuthenticatedCookieValuePrefix = ".";
        const string CookieName = "tmp";
        const string MachineKeyPurpose = "CookieTempDataProvider:{0}";
        const string Anonymous = "<anonymous>";

        public static event EventHandler<Exception> ValidationException;

        private readonly JsonSerializer jsonSerializer;

        public CookieTempDataProvider()
        {
            this.jsonSerializer = new JsonSerializer();
            this.jsonSerializer.Formatting = Formatting.None;
            this.jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
            this.jsonSerializer.TypeNameHandling = TypeNameHandling.Auto;
        }

        public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
        {
            byte[] bytes = SerializeWithJsonNetBson(values);
            //bytes = Compress(bytes);
            var value = Protect(bytes, controllerContext.HttpContext);
            IssueCookie(controllerContext, value);
        }

        public IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
        {
            var value = GetCookieValue(controllerContext);
            var bytes = Unprotect(value, controllerContext.HttpContext);
            if (bytes == null && value != null)
            {
                // failure, so remove cookie
                IssueCookie(controllerContext, null);
                return null;
            }
            else
            {
                //bytes = Decompress(bytes);
                return DeserializeWithJsonNetBson(bytes);
            }
        }

        private string GetCookieValue(ControllerContext controllerContext)
        {
            if (controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(CookieName))
            {
                HttpCookie c = controllerContext.HttpContext.Request.Cookies[CookieName];
                if (c != null)
                {
                    return c.Value;
                }
            }
            return null;
        }

        private void IssueCookie(ControllerContext controllerContext, string value)
        {
            // if we don't have a value and there's no prior cookie then exit
            if (value == null && !controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(CookieName)) return;

            HttpCookie c = new HttpCookie(CookieName, value)
            {
                // don't allow javascript access to the cookie
                HttpOnly = true,
                // set the path so other apps on the same server don't see the cookie
                Path = controllerContext.HttpContext.Request.ApplicationPath,
                // ideally we're always going over SSL, but be flexible for non-SSL apps
                Secure = controllerContext.HttpContext.Request.IsSecureConnection
            };

            if (value == null)
            {
                // if we have no data then issue an expired cookie to clear the cookie
                c.Expires = DateTime.Now.AddMonths(-1);
            }

            controllerContext.HttpContext.Response.Cookies.Add(c);
        }

        private string GetAnonMachineKeyPurpose()
        {
            return String.Format(MachineKeyPurpose, Anonymous);
        }

        private string GetMachineKeyPurpose(HttpContextBase ctx)
        {
            if (ctx.User == null || ctx.User.Identity == null || !ctx.User.Identity.IsAuthenticated) return GetAnonMachineKeyPurpose();
            return String.Format(MachineKeyPurpose, ctx.User.Identity == null ? "" : ctx.User.Identity.Name);
        }

        private string GetMachineKeyPurposeFromPrefix(string prefix, HttpContextBase ctx)
        {
            if (prefix == AnonymousCookieValuePrefix)
            {
                return GetAnonMachineKeyPurpose();
            }
            if (prefix == AuthenticatedCookieValuePrefix && ctx.User.Identity.IsAuthenticated)
            {
                return String.Format(MachineKeyPurpose, ctx.User.Identity.Name);
            }
            return null;
        }

        private string GetMachineKeyPrefix(HttpContextBase ctx)
        {
            if (ctx.User == null || ctx.User.Identity == null) return AnonymousCookieValuePrefix;

            return (ctx.User.Identity.IsAuthenticated) ?
                AuthenticatedCookieValuePrefix :
                AnonymousCookieValuePrefix;
        }

        private string Protect(byte[] data, HttpContextBase ctx)
        {
            if (data == null || data.Length == 0) return null;

            var purpose = GetMachineKeyPurpose(ctx);
            var value = MachineKey.Protect(data, purpose);

            var prefix = GetMachineKeyPrefix(ctx);
            return prefix + Convert.ToBase64String(value);
        }

        private byte[] Unprotect(string value, HttpContextBase ctx)
        {
            if (String.IsNullOrWhiteSpace(value)) return null;

            var prefix = value[0].ToString();
            var purpose = GetMachineKeyPurposeFromPrefix(prefix, ctx);
            if (purpose == null) return null;

            value = value.Substring(1);
            var bytes = Convert.FromBase64String(value);
            try
            {
                return MachineKey.Unprotect(bytes, purpose);
            }
            catch (CryptographicException ex)
            {
                if (ValidationException != null)
                {
                    ValidationException(this, ex);
                }
                return null;
            }
        }

        private byte[] SerializeWithJsonNetBson(IDictionary<string, object> data)
        {
            if (data == null || data.Keys.Count == 0) return null;

            var ms = new MemoryStream();
            
            using (var writer = new BsonWriter(ms))
            {
                this.jsonSerializer.Serialize(writer, data);
            }

            return ms.ToArray();
            
        }

        private IDictionary<string, object> DeserializeWithJsonNetBson(byte[] data)
        {
            if (data == null || data.Length == 0) return null;

            var ms = new MemoryStream(data);
            using (var reader = new BsonReader(ms))
            {
                return this.jsonSerializer.Deserialize<IDictionary<string, object>>(reader);
            }
        }
    }

from cookietempdata.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.