zoukankan      html  css  js  c++  java
  • Windows Phone 使用 HttpWebRequest 对象,通过POST 方式上传图片

           Windows Phone 客户端有时候需要把用户的图片保存到服务器端。本示例讲解如果把用户的头像,通过表单传输的方式,把用户的

    头像传递到 Web 端。当前的工程选择的是 OS7.1,在 WP8上通用,但需要注意的一点是,当前测试工程的 Web 端的地址是回环地址:

    localhost,所以如果在 WP8 的模拟器或者真机中测试时,需要真实 IP 地址,并且需要进行一些 IIS 的配置,这里就不多讲了。

          工程代码下载

       1、 首先写一个 Web 端 demo,固定端口号 10000,以便客户端可以调用该上传接口 API。

        1)定义一个名为 PhotoUploadController.ashx 的一般处理程序,用来接收用户的表单字段,并且把用户上传的图片保存到本地的 Images 文件夹中:

    namespace MyWebSite
    {
        /// <summary>
        /// 处理用户上传的图片,保存到网站的 Images 文件夹中
        /// </summary>
        public class PhotoUploadController : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                context.Response.ContentType = "text/plain";
    
                // 假设用户登录完成后,服务器端分配给用户的 token 凭据
                string access_token = "9c1302d0yarfasdfw3r234wgetr3qwt";
                
                if (context.Request.Params.AllKeys.Contains("access_token"))
                {
                    // 判断该用户是否有图片上传的权限
                    if (access_token == context.Request["access_token"])
                    {
                        // 获取图片
                           HttpPostedFile file = context.Request.Files[0];
                        String fileName = System.IO.Path.GetFileName(file.FileName);
                        file.SaveAs(context.Server.MapPath("~/") + "Images\\" + fileName);
    
                        // 操作成功,返回给客户端
                        context.Response.Write("ok");
                    }
                }
                else
                {
                    context.Response.Write("no access_token");
                }
            }
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }
    }


        2)然后定义一个 Default.aspx 文件,用来显示用户上传到服务端的图片,读取站点 Images 文件夹中的 photo.jpg 文件:

    <body style="background:#eaf0f3">
        <form id="form1" runat="server">
        <div style="400px;margin:0px auto; background:#dae7ef; padding:40px">
        <div style="text-align:center;color:#000000; font-size:25px">
            用户的头像
        </div>
            <div style="text-align:center; margin:40px 0px 40px 0px;">
    
                <!--显示 Images 文件夹中的头像文件-->
                <img src="/Images/photo.jpg" width="200" alt="没有头像" height="200" />
            </div>
        </div>
        </form>
    </body>

        当站点的 Images 文件夹中没有图片时,在 IE10 中的显示效果:

    2、编写客户端逻辑代码。

        1)用户图像的裁剪

            定义一个 PhotoCutPage.xaml 页面,引入 Microsoft.Phone.Controls.Toolkit 命名空间,使用其中的

      GestureListener 来处理用户的缩放、移动等手势操作:

     xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"


    页面的 xaml :

        <!--LayoutRoot 是包含所有页面内容的根网格-->
        <Canvas x:Name="LayoutRoot" Background="Transparent" Tap="cutCanvas_Tap">
           
            <!--该 Canvas 对象用来作为 WriteableBitmap 构造函数的 Element,来获取裁剪的图片-->
            <Canvas Width="360" Height="360" x:Name="cutCanvas" Canvas.Left="60" Canvas.Top="220" >
                <Image x:Name="imgSrc"  Stretch="UniformToFill"> <!--用户从图片库选择的图片-->
                    <Image.RenderTransform>
                        <CompositeTransform x:Name="transform" />
                    </Image.RenderTransform>
                    
                    <!--处理用户的拖拽、缩放等手势操作--> 
                    <toolkit:GestureService.GestureListener>                   
                            <toolkit:GestureListener PinchStarted="OnPinchStarted" PinchDelta="OnPinchDelta" 
    DragDelta
    ="Postcard_ManipulationDelta" PinchCompleted="GestureListener_PinchCompleted"
    DragCompleted
    ="GestureListener_DragCompleted"/> </toolkit:GestureService.GestureListener> </Image> </Canvas> <!--中间透明,四周半黑色透明的 .png 蒙板--> <Image Source="/Images/CutMaster.png"/> <Button Content="确定" Canvas.Left="259" Canvas.Top="707" Width="192" Click="Save_Click"/> <Button Content="取消" Canvas.Left="50" Canvas.Top="707" Width="192" Click="Cancel_Click"/> <!--及时显示给用户在进行完缩放、拖拽后的截图结果--> <Border x:Name="border" Visibility="Collapsed" HorizontalAlignment="Left" VerticalAlignment="Top"
    BorderBrush
    ="#ff1e1ee5" BorderThickness="2" Padding="2" Canvas.Left="178" Canvas.Top="5"> <Image Width="120" Height="120" x:Name="imgResult" /> </Border> </Canvas>


    相应的 C# 页面:

      public partial class PhotoCutPage : PhoneApplicationPage
        {
            public PhotoCutPage()
            {
                InitializeComponent();
                this.Loaded += PhotoCutPage_Loaded;
            }
    
            // 页面加载完成后,即让用户去图片库中选择图片
            void PhotoCutPage_Loaded(object sender, RoutedEventArgs e)
            {
                ChoosePicture();
            }
    
            // 从图片库选择图片文件
            void ChoosePicture()
            {
                try
                {
                    var task = new Microsoft.Phone.Tasks.PhotoChooserTask();
                    task.Completed += (s, evt) =>
                    {
                        if (evt.Error == null && evt.TaskResult == Microsoft.Phone.Tasks.TaskResult.OK)
                        {
                            BitmapImage bmpImage = new BitmapImage();
                            bmpImage.SetSource(evt.ChosenPhoto);
                            imgSrc.Source = bmpImage;
                        }
                    };
                    task.Show();
                }
                catch
                {
    
                }
            }
    
            // 用来保存用户裁剪过的图片,在进行 back 导航操作时,如果为 null
            // 则说明用户点击了“取消”,如果不为 null,则为“确定”
            public static WriteableBitmap writeBitmap = null;
    
            //double initialAngle;
            double initialScale; 
            // Pinch 开始
            private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
            {
                //initialAngle = transform.Rotation;
                initialScale = transform.ScaleX; // 每次触摸屏幕时,保存图片的 X 轴的缩放比例
            }
    
            // 用户两指进行缩放
            private void OnPinchDelta(object sender, PinchGestureEventArgs e)
            {
                //if (transform.ScaleX < 1 || transform.ScaleY < 1)
                //{
                //    return;
                //}
    
                //transform.Rotation = initialAngle + e.TotalAngleDelta;
                transform.ScaleX = initialScale * e.DistanceRatio; // 两只手指的缩放比例
                transform.ScaleY = initialScale * e.DistanceRatio; // 与 X轴保持相同,实现等比例缩放
            }
    
            // 图片的位移操作
            private void Postcard_ManipulationDelta(object sender, DragDeltaGestureEventArgs e)
            {
                //if (transform.TranslateX < 0 || transform.TranslateY < 0)
                //{
                //    return;
                //}
    
                //moving along X axis
                transform.TranslateX += e.HorizontalChange;
                //moving along Y axis
                transform.TranslateY += e.VerticalChange;
    
            }
    
            // 用户点击了 “确定”
            private void Save_Click(object sender, RoutedEventArgs e)
            {
                writeBitmap = new WriteableBitmap(cutCanvas, null);
    
                if (NavigationService.CanGoBack)
                {
                    NavigationService.GoBack();
                }
            }
    
            // 取消
            private void Cancel_Click(object sender, RoutedEventArgs e)
            {
                writeBitmap = null;
    
                if (NavigationService.CanGoBack)
                {
                    NavigationService.GoBack();
                }
            }
    
            // 两指缩放结束
            private void GestureListener_PinchCompleted(object sender, PinchGestureEventArgs e)
            {
                GetImgResult();
            }
    
            // 图片位移操作结束
            private void GestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
            {
                GetImgResult();
            }
    
            // 计算截图,并且显示到屏幕
            void GetImgResult()
            {
                if (imgSrc != null && imgSrc.Source != null)
                {
                    imgResult.Source = new WriteableBitmap(cutCanvas, null);
                    border.Visibility = System.Windows.Visibility.Visible;
                }
                else
                {
                    imgResult.Source = null;
                    border.Visibility = System.Windows.Visibility.Collapsed;
                }
            }
    
            //如果没有选择图片,则单击为选择
            private void cutCanvas_Tap(object sender, System.Windows.Input.GestureEventArgs e)
            {
                e.Handled = true;
    
                if (imgSrc.Source == null)
                {
                    ChoosePicture();
                }
            }
        }


        用户截图操作的显示效果:

    2)定义一个处理用户上传的类 UploadUserPhotoController.cs,用来把客户端的图片流 和其它一些表单字段

        通过 POST 的方式上传到服务器端,上传的数据类似于下面:

        //-----------------------------5d159c1302d0y0
        //Content-Disposition: form-data; name="access_token"
        //Content-Type: text/plain; charset=ISO-8859-1
        //Content-Transfer-Encoding: 8bit
    
        //9c1302d0yarfasdfw3r234wgetr3qwt
        //-----------------------------5d159c1302d0y0
        //Content-Disposition: form-data; name="avatar"; filename="photo.jpg"
        //Content-Type: jpeg
        //Content-Transfer-Encoding: binary

    通过字符串 -----------------------------5d159c1302d0y0 分割表单中的各个字段。

    UploadUserPhotoController 类的定义:

    namespace UploadPhotoDemo
    {
        /// <summary>
        /// 通过 POST 方式,上传图片和表单字段
        /// </summary>
        public class UploadUserPhotoController
        {
            // 上传完成后,触发的完成事件
            public event EventHandler OpenCompleted;
    
            // 保存当前需要上传的图片
            public WriteableBitmap bitmap4Upload;
    
    #if DEBUG
            //本地测试服务器地址
            string Uri = "http://localhost:10000/PhotoUploadController.ashx";
    #else
            string  Uri = "真实网络地址";
    #endif
    
            // 假设用户登录成功后,服务器分配给用户的 token 凭据
            string access_token = "9c1302d0yarfasdfw3r234wgetr3qwt";
    
            // 表单字段的分隔符
            string strBoundary = "---------------------------5d159c1302d0y0";
    
            public void Open()
            {
                HttpWebRequest request;
                request = WebRequest.Create(new Uri(Uri, UriKind.Absolute)) as HttpWebRequest;
                request.Method = "POST";
    
                request.ContentType = "multipart/form-data; boundary=" + strBoundary;
    
                IAsyncResult asyncResult = request.BeginGetRequestStream(new AsyncCallback(RequestStreamCallback), request);
            }
    
    
            private void RequestStreamCallback(IAsyncResult result)
            {
                HttpWebRequest request = result.AsyncState as HttpWebRequest;
    
                Stream requestStream = request.EndGetRequestStream(result);
    
                //StreamWriter streamWriter = new StreamWriter(requestStream);
    
                // 把 WriteableBitmap 对象保存到 Stream 对象中
                MemoryStream memoryStream = new MemoryStream();
                System.Windows.Media.Imaging.Extensions.SaveJpeg(bitmap4Upload, memoryStream, 
    bitmap4Upload.PixelWidth, bitmap4Upload.PixelHeight,
    0, 100); string postData = PrepareReqArgs(); // 组合表单数据 byte[] byteHead = Encoding.UTF8.GetBytes(postData); // 如果图片小于 4KB,则一次上次;如果大于 4KB,则分段上传,每次 4KB byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)memoryStream.Length))]; byte[] byteEnd = Encoding.UTF8.GetBytes("\r\n--" + strBoundary + "--\r\n"); requestStream.Write(byteHead, 0, byteHead.Length); memoryStream.Seek(0, SeekOrigin.Begin); int bytesRead = 0; while ((bytesRead = memoryStream.Read(buffer, 0, buffer.Length)) != 0) requestStream.Write(buffer, 0, bytesRead); requestStream.Write(byteEnd, 0, byteEnd.Length); requestStream.Close(); request.BeginGetResponse(new AsyncCallback(ResponseCallback), request); } string PrepareReqArgs() { StringBuilder sb = new StringBuilder(200); sb.Append("\r\n--"); sb.Append(strBoundary); sb.Append("\r\n"); sb.Append(@"Content-Disposition: form-data; name=""access_token"""); sb.Append("\r\n"); sb.Append(@"Content-Type: text/plain; charset=ISO-8859-1"); sb.Append("\r\n"); sb.Append("Content-Transfer-Encoding: 8bit"); sb.Append("\r\n\r\n"); sb.Append(this.access_token); //服务器端判断是否包含访问凭据 (Access_token) sb.Append("\r\n"); sb.Append("--"); sb.Append(strBoundary); sb.Append("\r\n"); sb.Append(@"Content-Disposition: form-data; name=""avatar""; filename=""photo.jpg"""); sb.Append("\r\n"); sb.Append("Content-Type: jpeg"); sb.Append("\r\n"); sb.Append("Content-Transfer-Encoding: binary"); sb.Append("\r\n\r\n"); return sb.ToString(); } // 上传完成 private void ResponseCallback(IAsyncResult result) { HttpWebRequest request = result.AsyncState as HttpWebRequest; WebResponse response = null; try { response = request.EndGetResponse(result); } catch (Exception ex) { Exception e = ex; // 没有网络链接,或者服务器端抛出异常 if (OpenCompleted != null) { OpenCompleted("serverError", null); } //_exception = ex.ToString(); return; } HttpWebResponse httpResponse = response as HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.OK) { Stream responseStream = response.GetResponseStream(); using (StreamReader sr = new StreamReader(responseStream)) { string Text = sr.ReadToEnd(); try { // 处理服务器返回参数 if (OpenCompleted != null) { OpenCompleted(Text, null); } } catch { // 处理异常 } } } else { //string Text = _exception; } } } }

    3)定义 WP工程中的 MainPage.xaml 页面,将用户选择的截图,在按钮事件中进行上传操作:

            // 使用 2) 中自定义图片上传操作的类
            UploadUserPhotoController uploadController;
    
            private void btnUpload_Click(object sender, RoutedEventArgs e)
            {
                if (uploadController == null)
                {
                    uploadController = new UploadUserPhotoController();
                    uploadController.OpenCompleted += uploadController_OpenCompleted;
                }
    
                // 将要上传的图片对象
                uploadController.bitmap4Upload = (imgPhoto.Source as System.Windows.Media.Imaging.WriteableBitmap);
    
                // 开始上传
                uploadController.Open();
            }

    上传操作完成后的回调:

           // 图片上传完成触发的回调
            void uploadController_OpenCompleted(object sender, EventArgs e)
            {
                if (sender != null && sender.ToString() == "ok")
                {
                    this.Dispatcher.BeginInvoke(delegate
                    {
                        MessageBox.Show("上传头像成功");
                    });
                }
                else
                {
                    this.Dispatcher.BeginInvoke(delegate
                    {
                        MessageBox.Show("上传头像失败");
                    });
                }
            }

    操作截图:

    上传成功后:

    网站端在刷新 Default.aspx 页面,读取用户上传的头像:

  • 相关阅读:
    Ubuntu安装最新版的nodejs
    Mac安装并破解OmniGraffle7
    Mac安装并破解StarUML
    Windows10使用Chocolatey安装mysql之后无法使用的解决办法
    Visual Studio编辑类模板的位置
    VS2017连接到中国区的Azure
    Windows上包管理器之Chocolatey初体验
    CENTOS7.3 64位架设使用MYSQL数据库的ASP.NET CORE网站
    从无到有开发自己的Wordpress博客主题---主页模板
    c# 获得方法的所属类(或调用者)的类名,方法名
  • 原文地址:https://www.cnblogs.com/hebeiDGL/p/3116536.html
Copyright © 2011-2022 走看看