在异步控制器中使用同步操作

Posted

技术标签:

【中文标题】在异步控制器中使用同步操作【英文标题】:Using synchronous operations in an asynchronous controller 【发布时间】:2013-12-04 19:30:39 【问题描述】:

我正在使用带有 4.5.1 框架和 MVC5 的 VS 2013。

我有一个 Web 服务,其中包含从客户端 MVC 控制器调用的方法。它们中的大多数是异步的,少数是同步的。 我的客户端控制器中出现同步的设计时编译错误。谁能告诉我为什么?

这是我在后端 Web 服务上进行异步和同步操作的代码。

public class CategoryController : AsyncController

异步

public async Task<Category> GetCategoryIDAsync(Int16 categoryid)
        
            try
            
                using (YeagerTechEntities DbContext = new YeagerTechEntities())
                
                    DbContext.Configuration.ProxyCreationEnabled = false;
                    DbContext.Database.Connection.Open();

                    var categoryEntity = await DbContext.Categories.Include("Projects").FirstOrDefaultAsync(f => f.CategoryID == categoryid);


                    Category category = null;
                    if (categoryEntity != null)
                    
                        category = new Category();
                        category.CategoryID = categoryEntity.CategoryID;
                        category.Description = categoryEntity.Description;
                        category.Projects = categoryEntity.Projects;
                    
                    else
                        throw new Exception("Category " + categoryid + " not found!");

                    return category;
                
            
            catch (Exception)
            
                throw;
            
        

同步 公共无效添加类别(类别猫) 尝试 使用 (YeagerTechEntities DbContext = new YeagerTechEntities())

                    Category category = new Category();

                    category.Description = cat.Description;

                    DbContext.Categories.Add(category);
                    DbContext.SaveChanges();
                
            
            catch (Exception)
            
                throw;
            
        

这是我的控制器前端的代码。

异步

 [Authorize(Roles = "Admin, AdminStage")]
 public async Task<ActionResult> SelectCategoryProjects([DataSourceRequest]DataSourceRequest request, string intCategoryID)
 
            if (Session["Culture"] != null)
                System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(Session["Culture"].ToString());

            try
            
                YeagerTechWcfService.Project[] projectList = await db.GetProjectByCategoryIDAsync(Convert.ToInt16(intCategoryID));

                var serializer = new javascriptSerializer();
                var result = new ContentResult();
                serializer.MaxJsonLength = Int32.MaxValue;
                result.Content = serializer.Serialize(projectList.ToDataSourceResult(request));
                result.ContentType = "application/json";

                return result;
 

同步

[HttpPost]
[Authorize(Roles = "Admin, AdminStage")]
public ActionResult UpsertCategory([DataSourceRequest]DataSourceRequest request, Category cat, Boolean blnInsert)

            if (TryUpdateModel(cat))
            
                try
                
                    if (blnInsert)
                        db.AddCategory(cat);
                    else
                        db.EditCategory(cat);

                    return Json(new[]  cat .ToDataSourceResult(request, ModelState));

我得到了典型的“最佳重载方法匹配”“有一些无效参数”的设计时编译错误,这很容易理解。

如果我点击“AddCategory”方法,会有一个蓝色的下划线表示:

在 YeagerTech.YeagerTechWcfService.YeagerTechWcfServiceClient 中为“AddCategory”生成方法存根

如果我这样做,它会在我的 Reference.cs 文件中添加一个内部方法,该方法是代理在添加服务引用时生成的,该方法在创建时在方法主体中出现典型的“未实现”错误。但是,我的 Reference.cs 文件中的 AddCategory 和 EditCategory 方法已经有两种方法。如果我遵守添加存根的要求,它会抱怨该方法已经存在并且是正确的。

这是在代理中生成的两种方法。第一个是同步的,第二个是异步的:

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IYeagerTechWcfService/AddCategory", ReplyAction="http://tempuri.org/IYeagerTechWcfService/AddCategoryResponse")]
void AddCategory(YeagerTech.YeagerTechWcfService.Category cat);

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IYeagerTechWcfService/AddCategory", ReplyAction="http://tempuri.org/IYeagerTechWcfService/AddCategoryResponse")]
System.Threading.Tasks.Task AddCategoryAsync(YeagerTech.YeagerTechWcfService.Category cat);

我需要做什么才能解决这个问题?

【问题讨论】:

有没有可能有两个Category 班级四处走动? PS - 这真的有好处吗? catch (Exception) throw; 模型项目中的方法的命名空间为:“YeagerTechModel.Category”。从服务返回时,为了检索数据,我需要指定以下代码:“YeagerTechWcfService.Category[] categoryList = await db.GetCategoriesAsync();”如果我尝试使用此代码“YeagerTechModel.Category[] = await db.GetCategoriesAsync();”,我会收到错误消息:无法将类型“YeagerTech.YeagerTechWcfService.Category[]”隐式转换为“YeagerTechModel.Category[]”。如果你注意到了,我确实说过代理生成了上面的帖子代码来保存数据。有什么想法吗? 通常,如果两个类在同一个层次结构中并且可以一次将一个转换为另一个 1,则数组无法自动转换。注意:在同一层次结构中具有相同名称的 2 个类完全是错误的,因此在这种情况下它们不应该相关。 【参考方案1】:

尝试将AsyncController 更改为ControllerAsyncController 不再需要。

【讨论】:

我按照建议进行了更改。但是,我收到了消息:“YeagerTech.YeagerTechWcfService.YeagerTechWcfServiceClient.AddCategory(YeagerTech.YeagerTechWcfService.Category)”的最佳重载方法匹配有一些无效参数。【参考方案2】:

通过改变传入方法的参数来解决。

之前,它的类型是:“YeagerTechModel.Category”。我将其更改为“YeagerTechWcdfService.Category”(由代理生成)并解决了设计时编译错误。

感谢你们为我指明了正确的方向:)

这是我将其更新为的代码:

[HttpPost]
        [Authorize(Roles = "Admin, AdminStage")]
        public ActionResult UpsertCategory([DataSourceRequest]DataSourceRequest request, YeagerTechWcfService.Category cat, Boolean blnInsert)
        
            if (TryUpdateModel(cat))
            
                try
                
                    if (blnInsert)
                        db.AddCategory(cat);
                    else
                        db.EditCategory(cat);

                    return Json(new[]  cat .ToDataSourceResult(request, ModelState));
                

【讨论】:

以上是关于在异步控制器中使用同步操作的主要内容,如果未能解决你的问题,请参考以下文章

同步与异步IO && blocking 与nonblocking 原理

同步与异步IO && blocking 与nonblocking 原理

协程,事件,队列,同步,异步,回调函数

Jsp页面中的异步与同步

C#有异步函数调用同步函数或同步函数调用异步函数

& 异步使用场景