TempData nie zapisuje obiektu

0

Witajcie,
Chcę między akcjami kontrolera przesłać modelstate w formie ViewData.

Szczerze mówiąc działało mi to do pewnego czasu. Niestety zmieniłem dużo rzeczy ostatnio i ciężko mi powiedzieć co to spowodowało. Teraz dostaję taki komunikat

InvalidOperationException: The 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer' cannot serialize an object of type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary'.

Stos

InvalidOperationException: The 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer' cannot serialize an object of type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary'.
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer.EnsureObjectCanBeSerialized(object item)
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer.Serialize(IDictionary<string, object> values)
Microsoft.AspNetCore.Mvc.ViewFeatures.CookieTempDataProvider.SaveTempData(HttpContext context, IDictionary<string, object> values)
Microsoft.AspNetCore.Mvc.ViewFeatures.TempDataDictionary.Save()
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.SaveTempDataFilter.SaveTempData(IActionResult result, ITempDataDictionaryFactory factory, IList<IFilterMetadata> filters, HttpContext httpContext)
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.SaveTempDataFilter.OnResultExecuted(ResultExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

A to moje dwie akcje. Chcę z ChangePassword do Index

ChangePassword

        public async Task<ActionResult> ChangePassword([Bind(Prefix = "ChangePasswordViewModel")]ChangePasswordViewModel model)
        {
            // In case we have simple errors - return
            if (!ModelState.IsValid)
            {
                TempData["ViewData"] = ViewData;
                return RedirectToAction("Index");
            }
            var user = await _userManager.FindByIdAsync(this.User.FindFirstValue(ClaimTypes.NameIdentifier));

            var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
            if (result.Succeeded)
            {
                //var user1 = await _userManager.FindByIdAsync(this.User.FindFirstValue(ClaimTypes.NameIdentifier));
                if (user != null)
                {
                    await SignInAsync(user, isPersistent: false);
                }
                return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess });
            }

            AddErrors(result);

            // In case we have login errors
            if (!ModelState.IsValid)
            {
                TempData["ViewData"] = ViewData;
                return RedirectToAction("Index");
            }

            var message = ManageMessageId.ChangePasswordSuccess;
            return RedirectToAction("Index", new { Message = message });
        }

index

        public async Task<ActionResult> Index(ManageMessageId? message)
        {

            if (TempData["ViewData"] != null)
            {
                ViewData = (ViewDataDictionary)TempData["ViewData"];
            }

            if (User.IsInRole("Admin"))
                ViewBag.UserIsAdmin = true;
            else
                ViewBag.UserIsAdmin = false;

            var user = await _userManager.FindByIdAsync(this.User.FindFirstValue(ClaimTypes.NameIdentifier));
            if (user == null)
            {
                return View("Error");
            }
            var userLogins = await _userManager.GetLoginsAsync(user);
            var otherLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            //var otherLoginsproviders = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            //var z = _db.UserData.Where(a => a.UserDataId == user.UserDataId).SingleOrDefault();

            var model = new ManageCredentialsViewModel
            {
                Message = message,
                HasPassword = this.HasPassword(),
                CurrentLogins = userLogins,
                OtherLogins = otherLogins,
                ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1,
                ChangeProfileViewModel = new ChangeProfileViewModel
                {
                    FirstName = user.FirstName,
                    LastName = user.LastName,
                    Address = user.Address,
                    CodeAndCity = user.CodeAndCity,
                    PhoneNumber = user.PhoneNumber,
                    Email = user.Email
                    
                }
            };

            return View(model);
        }

Błąd jest przy wyjściu z ChangePassword

w tym miejscu

            if (!ModelState.IsValid)
            {
                TempData["ViewData"] = ViewData;
                return RedirectToAction("Index");
            }

Pozdrawiam

0

Ale czemu próbujesz wsadzić ViewData do TempData?

0
somekind napisał(a):

Ale czemu próbujesz wsadzić ViewData do TempData?

Żeby przenieść między akcjami informację o błędach zawarych w modelstate

0

TempData obsługuje kilka podstawowych typów, więc złożonych raczej nie uda Ci się przesłać.

Ale ;) również obsługuje stringa, więc możesz zrobić obj to string

TempData["MyData"] = JsonConvert.SerializeObject(object);
0

@WeiXiao: To wtedy przy deserializacji przypisać to do TempData? Bo taki wynik wcześniej zwracał mi błąd ponieważ przyisywał null`a :/

0

Zamieniasz obiekt na stringa i przypisujesz, a później odczytujesz.

1
Phoryn napisał(a):
somekind napisał(a):

Ale czemu próbujesz wsadzić ViewData do TempData?

Żeby przenieść między akcjami informację o błędach zawarych w modelstate

Nie o to pytałem. Po prostu nie możesz wsadzić ViewData do TempData. Oba te gadżety służą do przechowywania w nich serializowalnych danych, najczęściej prostych napisów albo liczb, a nie siebie wzajemnie.

Ty próbowałeś zaparkować Passatem w bagażniku Golfa. No nie mogło się udać. ;)

0
somekind napisał(a):
Phoryn napisał(a):
somekind napisał(a):

Ale czemu próbujesz wsadzić ViewData do TempData?

Żeby przenieść między akcjami informację o błędach zawarych w modelstate

Nie o to pytałem. Po prostu nie możesz wsadzić ViewData do TempData. Oba te gadżety służą do przechowywania w nich serializowalnych danych, najczęściej prostych napisów albo liczb, a nie siebie wzajemnie.

Ty próbowałeś zaparkować Passatem w bagażniku Golfa. No nie mogło się udać. ;)

Rozumiem. Z tym, że jak pisałem, wcześniej to działało bez zarzutu. Niestety nie mogę stwierdzić co wpłynęło na to, ze teraz przestało to działać :(

Dobrze czy macie jakieś inne sposoby na przeniesienie informacji o błędzie podczas zmiany hasła do akcji indeks?

Robię to po to ponieważ mam w widoku index switch`a ,który wyłapuje komunikaty. Jeśli pojawi się w modelstate jakiś error z mojego enuma to wtedy wyrzucam użytkownikowi informację.

Pozdrawiam

0

Moze troche zmieni podejscie i informacji o bledzie nie wyrzucaj na indexie tylko na stronie od zmiany hasla? dodatkowo jak juz chcesz przenosic index to przenies do tempdata te rzeczy ktore Ci sa potrzebne a nie caly ViewData - takie niby ogolne podejscie zawsze okazuje sie problematyczne :)

0
tamtamtu napisał(a):

Moze troche zmieni podejscie i informacji o bledzie nie wyrzucaj na indexie tylko na stronie od zmiany hasla? dodatkowo jak juz chcesz przenosic index to przenies do tempdata te rzeczy ktore Ci sa potrzebne a nie caly ViewData - takie niby ogolne podejscie zawsze okazuje sie problematyczne :)

Znaczy musi to się odbywać w indeksie ponieważ indeks w tym wypadku to strona menadżera konta. Założyłem sobie, że wszystko będzie odbywało się w jednym miejscu. Więc są tam inputy do zmiany danych logowania oraz hasła. Błąd musi wyrzucić w tym miejscu :) Wiem, że może komplikuje sprawę ale przynajmniej nauczę się czegoś nowego :D

Spróbuję zmodyfikować więc tempdata.
Dziękuję!

0
Phoryn napisał(a):

Rozumiem. Z tym, że jak pisałem, wcześniej to działało bez zarzutu. Niestety nie mogę stwierdzić co wpłynęło na to, ze teraz przestało to działać :(

Zrób po prostu w ten sposób:

TempData["error"] = ViewData["error"];

O ile to w ogóle ma sens, żeby to wcześniej było w ViewData, skoro docelowo jest potrzebne w TempData - to nie można od razu tam wstawić?

0

Dla potomnych:

Niepotrzebnie komplikowałem sobie sprawę

dodałem dodatkową metodę, która dodaje błędy z identity(identity zwraca błędy w Result) do ModelState

        private void AddErrors(IdentityResult result)
        {
            List<string> list = new List<string>();

            foreach (var error in result.Errors)
            {

                list.Add(error.Description);
            }
            TempData["error"] = list;
        }

później w metodzie zmiany hasła wywołuję ją a dalej dla pewności dodaję

TempData.Keep("error");

(zauważyłem, że mi czasem usuwało wartość, muszę doczytać o tempdata, być może POST został tu przerwany i dlatego usunęło, nie wiem)

no i w indexie sprawdzenie i przypisanie do ViewData indexu

            if (TempData["error"] != null)
            {
                var z = (Array)TempData["error"];
                foreach(var x in z)
                {
                    ViewData.ModelState.AddModelError("password-error", x.ToString());
                }
            }

To pozwoliło mi w widoku korzystać z ViewData.ModelState i mogę sobie wyrzucać błędy.

Pozdrawiam!

0

Z tego co sprawdziłem to właśnie tu był błąd. Czyli TempData wygasa jeśli kończy się żądanie. Przejście do Index było już Getem.
Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1