I recently installed T4MVC using Nuget. I used to have an old version that worked fine, but I had a new requirement that required an asynchronous controller. After creating the asynchronous controller, my project will not compile due to the fact that it will be associated with t4. So I updated using Nuget.
Now the problem is that my controller worked fine until I updated t4mvc. After updating the compilation of the code, but when I call the asynchronous action, it returns after a long time and returns a huge amount of invalid data. Also, critically, if I set breakpoints in my controller, it no longer beats them ?! If I return my DocumentController.generated.cs file to the latest working version, everything will be fine.
Below is my old DocumentController.generated.cs, which works, and a new one, which does not.
Can someone help me figure out what's going on here? I began to rely on T4MVC because it is so good, however I really can not avoid these asynchronous actions.
OLD
NEW
// <auto-generated /> // This file was generated by a T4 template. // Don't change it directly as your change would get overwritten. Instead, make changes // to the .tt file (ie the T4 template) and save it to regenerate this file. // Make sure the compiler doesn't complain about missing Xml comments #pragma warning disable 1591 #region T4MVC using System; using System.Diagnostics; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Web; using System.Web.Hosting; using System.Web.Mvc; using System.Web.Mvc.Ajax; using System.Web.Mvc.Html; using System.Web.Routing; using T4MVC; namespace WebUI.Client.Controllers { public partial class DocumentController { [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public DocumentController() { } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] protected DocumentController(Dummy d) { } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] protected RedirectToRouteResult RedirectToAction(ActionResult result) { var callInfo = result.GetT4MVCResult(); return RedirectToRoute(callInfo.RouteValueDictionary); } [NonAction] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public System.Web.Mvc.JsonResult GetDocumentListCompleted() { return new T4MVC_JsonResult(Area, Name, ActionNames.GetDocumentListCompleted); } [NonAction] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public System.Web.Mvc.ActionResult GetDocumentThumbnailCompleted() { return new T4MVC_ActionResult(Area, Name, ActionNames.GetDocumentThumbnailCompleted); } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public DocumentController Actions { get { return MVC.Document; } } [GeneratedCode("T4MVC", "2.0")] public readonly string Area = ""; [GeneratedCode("T4MVC", "2.0")] public readonly string Name = "Document"; static readonly ActionNamesClass s_actions = new ActionNamesClass(); [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public ActionNamesClass ActionNames { get { return s_actions; } } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public class ActionNamesClass { public readonly string Index = "Index"; public readonly string GetDocumentListCompleted = "GetDocumentListCompleted"; public readonly string GetDocumentThumbnailCompleted = "GetDocumentThumbnailCompleted"; } static readonly ViewNames s_views = new ViewNames(); [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public ViewNames Views { get { return s_views; } } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public class ViewNames { public readonly string Index = "~/Views/Document/Index.aspx"; } } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public class T4MVC_DocumentController: WebUI.Client.Controllers.DocumentController { public T4MVC_DocumentController() : base(Dummy.Instance) { } public override System.Web.Mvc.ActionResult Index() { var callInfo = new T4MVC_ActionResult(Area, Name, ActionNames.Index); return callInfo; } public override System.Web.Mvc.JsonResult GetDocumentListCompleted(Web.Gateway.DocumentMetaDataCollection clientDocuments) { var callInfo = new T4MVC_JsonResult(Area, Name, ActionNames.GetDocumentListCompleted); callInfo.RouteValueDictionary.Add("clientDocuments", clientDocuments); return callInfo; } public override System.Web.Mvc.ActionResult GetDocumentThumbnailCompleted(System.IO.Stream document, string type) { var callInfo = new T4MVC_ActionResult(Area, Name, ActionNames.GetDocumentThumbnailCompleted); callInfo.RouteValueDictionary.Add("document", document); callInfo.RouteValueDictionary.Add("type", type); return callInfo; } } } #endregion T4MVC #pragma warning restore 1591
As requested here are stubs of my DocumentController class;
namespace WebUI.Client.Controllers { [Activated] [ConcurrentSessionDisabled] public partial class DocumentController : AsyncController { public readonly HashSet<string> ImageTypes = new HashSet<string>(new[] { "jpeg", "jpg", "png", "tif", "tiff", "bmp" }); public readonly HashSet<string> IgnoredImageTypes = new HashSet<string>(new[] { "tif", "tiff" }); public virtual ActionResult Index() { return RedirectToAction("List"); } public virtual ActionResult List() { return View(); } public virtual ActionResult Thumbnails(int id) { ViewData["documentId"] = id; return View(); } public void GetDocumentListAsync() { AsyncManager.Timeout = 30000; AsyncManager.OutstandingOperations.Increment(); Task.Factory.StartNew((state) => { Tuple<int, int> clientDetails = (Tuple<int, int>)state; DocumentMetaDataCollection clientDocuments = DocumentHelper.GetClientDocuments(clientDetails.Item1, clientDetails.Item2); AsyncManager.Parameters["clientDocuments"] = clientDocuments; AsyncManager.OutstandingOperations.Decrement(); }, new Tuple<int, int>(Profile.User().ClientId, Profile.User().CrmAccountId)); } public virtual JsonResult GetDocumentListCompleted(DocumentMetaDataCollection clientDocuments) { return Json(from document in clientDocuments.Documents select new { Id = document.Id, Values = document.Values, }, JsonRequestBehavior.AllowGet); } public void GetDocumentFilenamesAsync(int id) { AsyncManager.Timeout = 5000; AsyncManager.OutstandingOperations.Increment(); Task.Factory.StartNew((state) => { int documentId = (int)state; List<string> urls = DocumentHelper.GetUrlsForDocument(documentId); AsyncManager.Parameters["documentId"] = documentId; AsyncManager.Parameters["urls"] = urls; AsyncManager.OutstandingOperations.Decrement(); }, id); } public JsonResult GetDocumentFilenamesCompleted(int documentId, List<string> urls) { IDictionary<int, string> filenameToUrl = new Dictionary<int, string>(); Regex illegalCharacters = new Regex("[^A-Za-z0-9_[-]:]"); int idCounter = 0; foreach(string url in urls) { filenameToUrl.Add(++idCounter, url); } session_HoldDocumentUrls(documentId, filenameToUrl); return Json(from file in filenameToUrl select new { Name = filenameFrom(file.Value), Id = file.Key }); } private string filenameFrom(string url) { return url.Substring(url.LastIndexOf('/') + 1, url.Length - (url.LastIndexOf('/') + 1)); } public void GetThumbnailAsync(int documentId, int imageId) { AsyncManager.Timeout = 5000; AsyncManager.OutstandingOperations.Increment(); string url = session_GetDocumentUrls(documentId).First(f => f.Key == imageId).Value; Task.Factory.StartNew((state) => { string fileUrl = (string)state; thumbnailLoader(fileUrl); }, url); } private void thumbnailLoader(string fileUrl) { Stream document = DocumentHelper.GetDocument(fileUrl); string type = fileUrl.Substring(fileUrl.LastIndexOf('.') + 1, fileUrl.Length - (fileUrl.LastIndexOf('.') + 1)).ToLower(); if (ImageTypes.Contains(type)) { document = ImageHelper.ResizeImage(document, 210); type = "png"; } AsyncManager.Parameters["document"] = document; AsyncManager.Parameters["type"] = type; AsyncManager.OutstandingOperations.Decrement(); } public virtual ActionResult GetThumbnailCompleted(Stream document, string type) { switch (type) { case "png": return new FileStreamResult(document, "image/png"); case "pdf": return File(Links.Content.Images.pdf_256_png, "image/png"); default: return File(Links.Content.Images.document_256_png, "image/png"); } } public void FileAsync(int documentId, int imageId) { if (session_GetDocumentUrls(documentId) == null) { return; } string url = session_GetDocumentUrls(documentId).First(f => f.Key == imageId).Value; AsyncManager.Timeout = 5000; AsyncManager.OutstandingOperations.Increment(); Task.Factory.StartNew((state) => { string fileUrl = (string)state; Stream document = DocumentHelper.GetDocument(fileUrl); string type = fileUrl.Substring(fileUrl.LastIndexOf('.') + 1, fileUrl.Length - (fileUrl.LastIndexOf('.') + 1)).ToLower(); if (ImageTypes.Contains(type) && !IgnoredImageTypes.Contains(type)) { document = ImageHelper.ConvertToPng(document); type = "png"; } AsyncManager.Parameters["document"] = document; AsyncManager.Parameters["type"] = type; AsyncManager.OutstandingOperations.Decrement(); }, url); } public virtual ActionResult FileCompleted(Stream document, string type) { if (document == null || type == null) { return RedirectToAction("List"); } return new FileStreamResult(document, MimeHelper.Lookup("." + type)); } }
}
UPDATE 7/4/11
Hi David, I apologize for returning to you for so long, I studied some other works.
I managed to track down the problem and hopefully you can shed some light on it and possibly create a fix.
If you look at the second dump of the code above, this is the problem with this problem. The problem is what you created;
[NonAction] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public System.Web.Mvc.JsonResult GetDocumentListCompleted() { return new T4MVC_JsonResult(Area, Name, ActionNames.GetDocumentListCompleted); }
I did not think that MVC throws an error, but it was:
2011-04-07 15: 59: 38,921 [41] FATAL MvcApplication [(null)] - an uncaught System.Reflection.AmbiguousMatchException exception occurred: a search for the GetDocumentListCompleted method on the "DocumentController" controller failed because of the ambiguity between the following methods: System. Web.Mvc.JsonResult GetDocumentListCompleted (Web.Gateway.DocumentMetaDataCollection) by type WebUI.Client.Controllers.DocumentController System.Web.Mvc.JsonResult GetDocumentListCompleted () for type WebUI.Client.Controllers.DocuWntrol.Controllers.DocumentController. AsyncActionMethodSelector.GetMethodByName (String methodName)
So, as I understand it, the MVC system has an ambiguous match with my code and the code you created.
If I comment on your code above, everything will work fine again.
Do you now understand the nature or problem? Could it be fixed?
Greetings
Ryan.