1

我正在使用 android 尝试将文件上传到我的服务器,该服务器正在运行 asp.net mvc4 web api。我的android类如下:

package com.example.wsis;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class UploadImage extends Activity implements View.OnClickListener {
    Button upload_btn, uploader;
    Uri currImageURI;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_upload_image);
        upload_btn = (Button) this.findViewById(R.id.btnUpload);
        uploader = (Button) this.findViewById(R.id.btnUploadFile);
        upload_btn.setOnClickListener(this);
        uploader.setOnClickListener(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.upload_image, menu);
        return true;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btnUpload:
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent, "Select Picture"),1);
            break;

    case R.id.btnUploadFile:
        HttpUploader uploader = new HttpUploader();
        try {
          String image_name = uploader.execute(getRealPathFromURI(currImageURI)).get();        
        } catch (InterruptedException e) {
          e.printStackTrace();
        } catch (ExecutionException e) {
          e.printStackTrace();
        }
        break;
    }
    }

    // To handle when an image is selected from the browser
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            if (requestCode == 1) {
                // currImageURI is the global variable I’m using to hold the content:
                currImageURI = data.getData();
                System.out.println("Current image Path is ----->" + getRealPathFromURI(currImageURI));
                TextView tv_path = (TextView) findViewById(R.id.path);
                tv_path.setText(getRealPathFromURI(currImageURI));
            }
        }
    }

    //Convert the image URI to the direct file system path of the image file
    public String getRealPathFromURI(Uri contentUri) {
        String [] proj={MediaStore.Images.Media.DATA};
        android.database.Cursor cursor = managedQuery( contentUri,
                proj,     // Which columns to return
                null,     // WHERE clause; which rows to return (all rows)
                null,     // WHERE clause selection arguments (none)
                null);     // Order-by clause (ascending by name)
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }

       public class HttpUploader extends AsyncTask<String, Void, String> {

           @Override
           protected String doInBackground(String... path) {

                String outPut = null;

                for (String sdPath : path) {

                    Bitmap bitmapOrg = BitmapFactory.decodeFile(sdPath);
                    ByteArrayOutputStream bao = new ByteArrayOutputStream();

                    //Resize the image
                    double width = bitmapOrg.getWidth();
                    double height = bitmapOrg.getHeight();
                    double ratio = 400/width;
                    int newheight = (int)(ratio*height);

                    System.out.println("———-width" + width);
                    System.out.println("———-height" + height);

                    bitmapOrg = Bitmap.createScaledBitmap(bitmapOrg, 400, newheight, true);

                    //Here you can define .PNG as well
                    bitmapOrg.compress(Bitmap.CompressFormat.JPEG, 95, bao);
                    byte[] ba = bao.toByteArray();
                    String ba1 = Base64.encodeToString(ba, Base64.NO_WRAP);
                    System.out.println("uploading image now ——–" + ba1);

                    ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
                    nameValuePairs.add(new BasicNameValuePair("image", ba1));

                    try {
                        HttpClient httpclient = new DefaultHttpClient();
                        HttpPost httppost = new HttpPost("http://proopt.co.za.winhost.wa.co.za/api/Files/");
                        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

                        HttpResponse response = httpclient.execute(httppost);
                        HttpEntity entity = response.getEntity();                

                        // print response
                        outPut = EntityUtils.toString(entity);
                        Log.i("GET RESPONSE—-", outPut);

                        //is = entity.getContent();
                        Log.e("log_tag ******", "good connection");

                        bitmapOrg.recycle();

                    } catch (Exception e) {
                        Log.e("log_tag ******", "Error in http connection " + e.toString());
                    }
                }
                return outPut;

           }
       }
}

而我的 asp.net 控制器类是:

public class FilesController : ApiController
    {
        // GET api/files
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/files/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/files
        public HttpResponseMessage Post(string filename)
        {
            var task = this.Request.Content.ReadAsStreamAsync();
            task.Wait();
            Stream requestStream = task.Result;

            try
            {
                Stream fileStream = File.Create(HttpContext.Current.Server.MapPath("~/" + filename));
                requestStream.CopyTo(fileStream);
                fileStream.Close();
                requestStream.Close();
            }
            catch (IOException)
            {
              //  throw new HttpResponseException("A generic error occured. Please try again later.", HttpStatusCode.InternalServerError);
            }

            HttpResponseMessage response = new HttpResponseMessage();
            response.StatusCode = HttpStatusCode.Created;
            return response;
        }

        // PUT api/files/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/files/5
        public void Delete(int id)
        {
        }
    }

这是 global.asax.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace WSISWebService
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

        }

        public static void RegisterRoutes(RouteCollection routes)
        {

            routes.MapHttpRoute(

                name: "DefaultApi",

                routeTemplate: "{controller}/{filename}",

                defaults: new { filename = RouteParameter.Optional }

            );

        }
    }
}

我非常渴望得到这个工作,有人可以帮助我吗?

更新:我已经设法“找到” post 方法,但我似乎无法让 android 发送文件,有人可以帮我编写服务器端 post 方法吗???

4

1 回答 1

1

您发布到的 URL 正在找到您的控制器类,因为您的默认路由映射将“/api/Files/”映射到 FilesController。但是,您的 URI 不能识别“操作”,例如“/api/Files/Post”。

顺便说一句,ASP.NET MVC 应用程序中的默认路由是“/{controller}/{action}”,并且通常具有默认值“controller=Default”和“action=Index”。因此,默认情况下,“/api/Files”会寻找名为“Index”的操作方法,但您的 FilesController 没有这样的方法。

简短的答案:

  1. 将“/Post”添加到您要发布到的 URL 的末尾
  2. 或者,将您的“Post()”操作方法重命名为“Index()”

长答案:

  1. 查看设置路由的 Global.asax.cs 并考虑设置一些非常自定义的路由,这样您就可以让您的 URI 看起来像您想要的那样,独立于您如何组织您的控制器类和操作方法。

现在您已经发布了 Global.asax.cs,让我们检查一下您拥有的一个路由模板:

"{controller}/{filename}"

您是在告诉 MVC,当您有一个看起来像“/something/somethingelse”的 URL 时,可以使用“something”并将其用作控制器名称,并将“somethingelse”用作文件名。您的路线中没有任何内容可以确定要调用的操作。

现在,如果您不希望调用任何其他操作,那没关系。在这种情况下,您可以在路由的默认值中硬编码操作“发布”:

defaults: new { filename = RouteParameter.Optional, action = "Post" }

如果您希望能够调用您拥有的其他操作方法(例如 Put、Delete 等),那么您可以修改您的 URL 模式(和调用 URL)以包含“操作”:

"{controller}/{action}/{filename}" // E.g. url: "/Files/Post/myfilename.txt"

或者,也许您真的希望所有内容始终通过 FilesController,在这种情况下,您可以将控制器设置为默认值,并让路由模板只期望操作和文件名(例如 .../Post/myfilename.txt):

        routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "{action}/{filename}",
            defaults: new { filename = RouteParameter.Optional, controller = "Files"}
        );
于 2013-10-03T12:49:56.857 回答