简体   繁体   English

调整图像大小的异步任务

[英]Asynchronous task for image resize

This is my image resizer class: 这是我的图像缩放器类:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Threading.Tasks;
public class ImageResize
{
    private static ImageCodecInfo jpgEncoder;
    public async static void ResizeImage(string inFile, string outFile,
    double maxDimension, long level)
    {
        byte[] buffer;
        using (Stream stream = new FileStream(inFile, FileMode.Open))
        {
            buffer = new byte[stream.Length];
            await Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead,
            buffer, 0, buffer.Length, null);
        }
        using (MemoryStream memStream = new MemoryStream(buffer))
        {
            using (Image inImage = Image.FromStream(memStream))
            {

                double width;
                double height;
                if (inImage.Height < inImage.Width)
                {
                    width = maxDimension;
                    height = (maxDimension / (double)inImage.Width) * inImage.Height;
                }
                else
                {
                    height = maxDimension;
                    width = (maxDimension / (double)inImage.Height) * inImage.Width;
                }
                using (Bitmap bitmap = new Bitmap((int)width, (int)height))
                {
                    using (Graphics graphics = Graphics.FromImage(bitmap))
                    {

                        graphics.SmoothingMode = SmoothingMode.HighQuality;
                        graphics.InterpolationMode =
                        InterpolationMode.HighQualityBicubic;
                        graphics.DrawImage(inImage, 0, 0, bitmap.Width, bitmap.Height);

                        if (inImage.RawFormat.Guid == ImageFormat.Jpeg.Guid)
                        {
                            if (jpgEncoder == null)
                            {
                                ImageCodecInfo[] ici =
                                ImageCodecInfo.GetImageDecoders();
                                foreach (ImageCodecInfo info in ici)
                                {
                                    if (info.FormatID == ImageFormat.Jpeg.Guid)
                                    {
                                        jpgEncoder = info;
                                        break;
                                    }
                                }
                            }
                            if (jpgEncoder != null)
                            {
                                EncoderParameters ep = new EncoderParameters(1);
                                ep.Param[0] = new EncoderParameter(Encoder.Quality,
                                level);
                                bitmap.Save(outFile, jpgEncoder, ep);
                            }
                            else
                                bitmap.Save(outFile, inImage.RawFormat);
                        }
                        else
                        {
                            //
                            // Fill with white for transparent GIFs
                            //
                            graphics.FillRectangle(Brushes.White, 0, 0, bitmap.Width,
                            bitmap.Height);
                            bitmap.Save(outFile, inImage.RawFormat);
                        }
                    }
                }
            }
        }
    }
}

And this is my register button server click: 这是我的注册按钮服务器单击:

    HttpPostedFile file = Request.Files["ctl00$cph$postFile"];
    string FileName = "";

    if (file.ContentLength > 0)
    {
        string[] ValidExt = { ".jpg", ".jpeg" };

        string fileExt = Path.GetExtension(file.FileName).ToLower();

        if (Array.IndexOf(ValidExt, fileExt) < 0)
        {
            return;
        }
        if (file.ContentLength / 1024 > 5120)
        {
            return;
        }
        string path = Server.MapPath("~/upload/image_upload/ads/");
        string[] s = file.FileName.Split('\\');

        FileName = System.IO.Path.GetFileName(s[s.Length - 1]);
        while (System.IO.File.Exists(path + FileName))
        {
            Random r = new Random();
            int rn = (DateTime.Now + r.Next().ToString()).GetHashCode();
            FileName = rn + " " + FileName;
        }
        string FullPath = path + FileName;
        file.SaveAs(FullPath);
        ImageResize.ResizeImage(FullPath, FullPath, 800, 80);
        string thPath = path + "th\\" + FileName;
        file.SaveAs(thPath);
        ImageResize.ResizeImage(thPath, thPath, 300, 90);

    }
    SqlConnection con = new SqlConnection(cs);

    StringBuilder sb = new StringBuilder();
    sb.Append("BEGIN TRY BEGIN TRANSACTION");
    sb.Append(" declare @result bit=0; declare @ad_id int;");
    sb.Append("INSERT INTO tbl_ads(ad_title,ad_brief,ad_text,ad_pic,ad_datesave,ad_is_accept,ad_is_show,ad_visit,ad_type,ad_user,ad_is_slide)");
    sb.Append(" VALUES(@ad_title,@ad_brief,@ad_text,@ad_pic,@ad_datesave,@ad_is_accept,@ad_is_show,@ad_visit,@ad_type,@ad_user,@ad_is_slide);");
    sb.Append("set @ad_id=SCOPE_IDENTITY();");

    SqlCommand cmd = new SqlCommand();
    cmd.Connection = con;

    cmd.Parameters.AddWithValue("@ad_title", txt_title.Value);
    cmd.Parameters.AddWithValue("@ad_brief", txt_brief.Value);
    cmd.Parameters.AddWithValue("@ad_text", txt_full.Value);
    cmd.Parameters.AddWithValue("@ad_pic", FileName);
    cmd.Parameters.AddWithValue("@ad_datesave", PersianDate.GetDate(0));
    cmd.Parameters.AddWithValue("@ad_is_accept", chk_accept.Checked);
    cmd.Parameters.AddWithValue("@ad_is_show", chk_show.Checked);
    cmd.Parameters.AddWithValue("@ad_visit", 0);
    cmd.Parameters.AddWithValue("@ad_type", lst_type.Value);
    cmd.Parameters.AddWithValue("@ad_user", -1*(int)Session["u_id"]);
    cmd.Parameters.AddWithValue("@ad_is_slide", chk_slide.Checked);


    string[] SubcatIds = inp_subcats.Value.Split(',');
    string[] StateIds = inp_states.Value.Split(',');
    string[] CityIds = inp_cities.Value.Split(',');


    if (CatIds[0] != "")
    {
        for (int i = 0; i < CatIds.Length; i++)
        {
            cmd.Parameters.AddWithValue("@cat_id" + i, CatIds[i]);
            sb.Append("INSERT INTO tbl_inf_adcat(ad_id,cat_id) VALUES(@ad_id,@cat_id" + i + ");");
        }
    }

    if (SubcatIds[0] != "")
    {
        for (int i = 0; i < SubcatIds.Length; i++)
        {
            cmd.Parameters.AddWithValue("@subcat_id" + i, SubcatIds[i]);
            sb.Append("INSERT INTO tbl_inf_adsubcat(ad_id,subcat_id) VALUES(@ad_id,@subcat_id" + i + ");");
        }
    }

    if (StateIds[0] != "")
    {
        for (int i = 0; i < StateIds.Length; i++)
        {
            cmd.Parameters.AddWithValue("@state_id" + i, StateIds[i]);
            sb.Append("INSERT INTO tbl_inf_adstate(ad_id,state_id) VALUES(@ad_id,@state_id" + i + ");");
        }
    }

    if (CityIds[0] != "")
    {
        for (int i = 0; i < CityIds.Length; i++)
        {
            cmd.Parameters.AddWithValue("@city_id" + i, CityIds[i]);
            sb.Append("INSERT INTO tbl_inf_adcity(ad_id,city_id) VALUES(@ad_id,@city_id" + i + ");");
        }
    }


    sb.Append("COMMIT set @result=1 select @result  END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK select  @result END CATCH");

    cmd.CommandText = sb.ToString();

    try
    {

        con.Open();

        bool result = Convert.ToBoolean(cmd.ExecuteScalar());

        if (result == true)
        {
            ClientAlert.modalBoxInfo(this, "success");

        }
        else
        {
            ClientAlert.modalBoxAlert(this, "error");
        }

    }
    catch
    {
        ClientAlert.modalBoxAlert(this, "error");
    }
    finally
    {
        con.Close();
    }

}

But when I want to run this method an error occur : 但是,当我想运行此方法时,会发生错误:

An asynchronous module or handler completed while an asynchronous operation was still pending. 异步模块或处理程序在异步操作仍挂起时完成。

I used Async="true" in the page directive and I test it in visual studio but in the real host it has that error. 我在page指令中使用了Async =“ true” ,并在Visual Studio中对其进行了测试,但在实际主机中却存在该错误。 Is it because I used a transaction? 是因为我使用了交易吗? Advance Regards. 提前致意。

No, it's because of the 不,是因为

await Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead,
        buffer, 0, buffer.Length, null);

The tricky part is that your async method is returning void . 棘手的部分是您的async方法返回void That's a big no-no unless you know what you're doing (which you obviously don't right now). 除非您知道自己在做什么(这显然您现在还不知道),否则这是一个很大的禁忌。 Have it return Task instead, and the same for all the other callers all the way to the request handler itself. 让它返回Task ,对所有其他调用者直到请求处理程序本身都返回Task That will allow you to marshal the awaited callback back to the original request thread - otherwise, the request will simply end, causing the callback to work on an already completed request. 这将允许您将等待的回调封送回原始请求线程-否则,请求将简单结束,从而使回调对已完成的请求起作用。

For await code to work correctly, you need to have this unbroken chain of Task -returning methods, as simple as that. 为了使await代码正常工作,您需要具有如此简单的Task返回方法链。 Otherwise, at some point you're just calling a void -returning method that returns immediately and then you continue on the next statement, while the background task is still running. 否则,有时您只是调用void -returning方法,该方法立即返回,然后在后台任务仍在运行时继续执行下一条语句。

Or , if you want this to be a fire-and-forget action, without having the request wait for the resize to be done, you can force the await not to try marshalling back to the request thread: 或者 ,如果您希望这是一劳永逸的操作,而不必等待请求完成调整大小,则可以强制await不要尝试将其编组回请求线程:

await Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead,
        buffer, 0, buffer.Length, null).ConfigureAwait(false);

Also, it's a bad idea to save the input file to a file first. 另外,先将输入文件保存到文件中也是一个坏主意。 You have all you need to work with the input stream directly, why would you want to save an intermediate file? 您拥有直接使用输入流所需的全部功能,为什么还要保存一个中间文件? It could quite easily fail on some file locking issue. 在某些文件锁定问题上,它很容易失败。

And , when using such fire-and-forget tasks, make sure you do proper error handling. 并且 ,在使用此类“一劳永逸”任务时,请确保进行正确的错误处理。 Depending on .NET framework version and configuration, an unhandled exception in a non-awaited Task will kill the whole process. 根据.NET Framework版本和配置,未等待的Task未处理的异常将杀死整个过程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM