Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
439 views
in Technique[技术] by (71.8m points)

ios - Upload image from iPhone to server using WCF service using SOAP

hiii, i'm using wcf SOAP services for my app and i send the request like below.

postStr = [NSString stringWithFormat:@"<?xml version="1.0"?>
"
           "<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
"
           "<s:Body>
"
           "<InsUpdDelActivityInfo xmlns="http://tempuri.org/">
"
           "<objEventsContent xmlns:d4p1="http://schemas.datacontract.org/2004/07/iCampuslite.Model.ActivityStream" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
"
           "<d4p1:ActCommentId i:nil="true" />
"
           "<d4p1:ActSubTypeCd i:nil="true" />
"
           "<d4p1:ActType>Status</d4p1:ActType>
"
           "<d4p1:ActTypeCd>1</d4p1:ActTypeCd>
"
           "<d4p1:ActivityAnswersList />
"
           "<d4p1:ActivityComments />
"
           "<d4p1:ActivityId i:nil="true" />
"
           "<d4p1:ActivityLike />
"
           "<d4p1:ActivityName>%@</d4p1:ActivityName>
"
           "<d4p1:ActivityStreamImagesBytes>%@</d4p1:ActivityStreamImagesBytes>
"
           "<d4p1:AnswerDesc i:nil="true" />
"
           "<d4p1:AnswerId>0</d4p1:AnswerId>
"
           "<d4p1:CommentDesc i:nil="true" />
"
           "<d4p1:CommentId i:nil="true" />
"
           "<d4p1:CreatedUserId>%@</d4p1:CreatedUserId>
"
           "<d4p1:CreatedUserName i:nil="true" />
"
           "<d4p1:FileOrLinkName i:nil="true" />
"
           "<d4p1:IsLiked>0</d4p1:IsLiked>
"
           "<d4p1:IsTotalSchool i:nil="true" />
"
           "<d4p1:LikeCount>0</d4p1:LikeCount>
"
           "<d4p1:LinkImage i:nil="true" />
"
           "<d4p1:ObjTypeCdId i:nil="true" />
"
           "<d4p1:ObjTypeId i:nil="true" />
"
           "<d4p1:OperationMode>I</d4p1:OperationMode>
"
           "<d4p1:OperationType i:nil="true" />
"
           "<d4p1:OperationTypeId i:nil="true" />
"
           "<d4p1:OrganizationId>%@</d4p1:OrganizationId>
"
           "<d4p1:OtherActivityId i:nil="true" />
"
           "%@
"
           "</objEventsContent>
"
           "<ismobile>true</ismobile>
"
           "</InsUpdDelActivityInfo>
"
           "</s:Body>
"
           "</s:Envelope>", statusText, [appDelegateObj.loginUserInfoDict valueForKey:@"a:UserId"], [appDelegateObj.loginUserInfoDict valueForKey:@"a:OrgId"], workspaceStr];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@iCampusliteMobileService/ActivityStreamSl.svc", appDelegateObj.baseURL]]];
NSString *messageLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postStr length]];
[request addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"http://tempuri.org/IActivityStreamSl/InsUpdDelActivityInfo" forHTTPHeaderField:@"SOAPAction"];
[request addValue:messageLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[postStr dataUsingEncoding:NSUTF8StringEncoding]];
NSError *error = nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];

in the above request there is an element ActivityStreamImagesBytes which is base64binary parameter i have to pass the image.

I've tried using many different formats.

here is wcf service screenshot here

and here is the server side code

public string byteArrayToImage(byte[] byteArrayIn,string fileName)
    {
        if (byteArrayIn != null)
        {
            ActivityStreamSl.LogMsg("Byte Array Count : "+byteArrayIn.Length.ToString(), "D:\log.txt");
            var serverfile = "D:somepathsomepathsomefolder";
            var getfile = HelperClass.Filesavehelper(Constants.UploadPaths.ActivityStream, "testfilename.png", serverfile);

            FileStream file = new FileStream(getfile, FileMode.Create);
            file.Write(byteArrayIn, 0, byteArrayIn.Length);
            file.Close();
            file.Dispose();
            return getfile;
        }
        else
        {
            ActivityStreamSl.LogMsg("Byte array is null","D:\log.txt");
        }
        return "";
    }

the server is expecting a byte array and i dont know how to send it? And i dont know what a base64binary data type is? Do I have to send the base64 encoded string or byte array or just data of image from NSData *data = UIImageJPEGRepresentation([UIImage imageNamed:@"popular.png"], 0.7);

Any help is appreciable

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The WCF service clearly asks for base64binary so you have to send it in base64binary only.

base64binary is nothing but base64 encoded binary data.

1) Convert the image to binary using the following code snippet

NSData *binaryImageData  = UIImageJPEGRepresentation([UIImage imageNamed:@"Photo.png"], 0.0);

2) Encode the binary into base64 format

Here is the class that I use to handle base64 binary and UIImage

 @interface base64BinaryandImagehandler:NSObject
   +(NSString *) base64BinaryStringFromBinaryData: (NSData *)data length: (int)length;
   +(UIImage*)Base64BinaryToImage:(NSString *)Base64;
 @end


 @implementation base64BinaryandImagehandler:NSObject
      static char base64EncodingTable[64] = {
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
     };

 +(NSString *) base64BinaryStringFromBinaryData: (NSData *)data length: (int)length{          

 unsigned long ixtext, lentext;

    long ctremaining;

    unsigned char input[3], output[4];

    short i, charsonline = 0, ctcopy;

    const unsigned char *raw;

    NSMutableString *result;

    lentext = [data length];

    if (lentext < 1)
        return @"";

    result = [NSMutableString stringWithCapacity: lentext];

    raw = [data bytes];

    ixtext = 0;

    while (true) {

        ctremaining = lentext - ixtext;

        if (ctremaining <= 0)
            break;

        for (i = 0; i < 3; i++) {
            unsigned long ix = ixtext + i;
            if (ix < lentext)
                input[i] = raw[ix];
            else
                input[i] = 0;
        }

        output[0] = (input[0] & 0xFC) >> 2;

        output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);

        output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);

        output[3] = input[2] & 0x3F;

        ctcopy = 4;

        switch (ctremaining) {
            case 1:
                ctcopy = 2;
                break;

            case 2:
                ctcopy = 3;
                break;
        }

        for (i = 0; i < ctcopy; i++)
            [result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];

        for (i = ctcopy; i < 4; i++)
            [result appendString: @"="];

        ixtext += 3;

        charsonline += 4;

        if ((length > 0) && (charsonline >= length))
            charsonline = 0;
    }
    return result;
      }

  +(UIImage*)Base64BinaryToImage:(NSString *)Base64{      


        NSString* base64String=[[NSString alloc]initWithFormat:@"data:image/png;base64,%@",Base64];

       NSURL *base64url = [NSURL URLWithString:base64String];

       NSData *imageData = [NSData dataWithContentsOfURL:base64url];

       UIImage *img=[UIImage imageWithData:imageData];

      return img;
     }
 @end 

Here is the way to convert binary into base64binary

NSString *Base64Binary=[base64BinaryandImagehandler base64BinaryStringFromBinaryData:binaryImageData length:binaryImageData.length];

You can find more about here as well

Here is the base64 encoding and decoding part in C#

public static string Base64Encode(string plainText) {
  var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
  return System.Convert.ToBase64String(plainTextBytes);
}

public static string Base64Decode(string base64EncodedData) {
  var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
  return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}

Anyhow you can ignore about the C# part since you are doing iPhone part only.

You can use the below link to test if your encoded base 64 is proper.

base64toimage converter

Update 1 Here is the code that will confirm if the received string is in base64 format or not

   private bool IsBase64String(string str){
    try{
    // If not exception is caught, then it is a base64 string
    MemoryStream stream = new MemoryStream(Convert.FromBase64String(str));
    return true;
    }
    catch{
    // If exception is caught, then I assumed it is a normal string
    return false;
    }
    }

Reference

The below code will create a image under Images folder for the given arriving base64 data and filename of your choice for example duraiamuthan.jpg and return the path of the image so that you can update it in the DB (It will check if the arriving the data is in base64 or binary[just in case WCF framework converts the base64 to binary internally])

  public string Getpath_CreateImageFromEncodedData(string Base64EncodedData, string fileName)
        {
        string fileHandle = "";
        try
        {
            if(IsBase64String(Base64EncodedData))
            byte[] imageBytes = Convert.FromBase64String(Base64EncodedData);
            else
            byte[] imageBytes= Base64EncodedData;

            MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);

            ms.Write(imageBytes, 0, imageBytes.Length);

            fileHandle = System.Web.HttpContext.Current.Server.MapPath("Images/" + fileName);

            FileStream fsObj = new FileStream(fileHandle, FileMode.Create, FileAccess.Write);

            ms.WriteTo(fsObj);

            fsObj.Close();

            ms.Close();

            return fileHandle;

        }
        catch (Exception ex)
        {
           return "";
        }

    }        

Update 2 (for timeout issues)

  • NSURLRequest and NSMutableURLRequest default timeout period is 60 seconds depending upon the Internet connectivity,Internet Traffic congestiion at webserver,ImageCreating time and all it may not be enough.so you can set the value higher than that using the following syntax [urlReqObj setTimeoutInterval:180]; the timeout interval is in seconds only.

  • Increase the ConnectionTimeout in IIS default value is 120 seconds sometimes if so many requests queue in the request will fail.Increasing the ConnectionTimeOut will help.(This timeout is also for idle time of a connection).To set it in IIS Advanced Settings Click on your service in IIS Manager -> Advanced Settings -> Connection Limits and there you can set the timeout or you could simple override the connection timeout in web.config.

  • Turn on Keep-alive in IIS so that same connection is reused thus increasing the effeceincy of IIS. Click on your service in IIS Manager -> Advanced Settings -> Connection Limits -> Enable HTTP Keep-Alives

  • If you plan to store the binary of image in DB.you can increase the DB connectiontimeout in connectionstring or you can increase the sqlcommandtimeout

Hope this helps. Feel free to ask if you have any doubts


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...