diff --git a/.gitignore b/.gitignore index 596c2d03..9d7dbafa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,10 @@ *.swp *.suo +TestResult.xml test-results -csharp-sdk.userprefs +Qiniu.LocalTest +*.userprefs bin obj diff --git a/CHANGELOG.md b/CHANGELOG.md index 57666d17..4ded2049 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ## CHANGE LOG +### v6.0.3 + +2014-01-06 #issue[40](https://github.com/qiniu/csharp-sdk/pull/40) + +- 添加pfop请求(DO)及状态查询接口(QueryPfopStatus) +- 添加NET2.0、NET3.5、NET4.0支持 + ### v6.0.2 2013-11-18 #issue[38](https://github.com/qiniu/csharp-sdk/pull/38) diff --git a/Docs/README.md b/Docs/README.md index d3dae917..407ad2bf 100644 --- a/Docs/README.md +++ b/Docs/README.md @@ -5,7 +5,7 @@ title: C# SDK 使用指南 # C# SDK 使用指南 -此 C# SDK 适用于.net framework>4.0版本,基于 [七牛云存储官方API](http://docs.qiniu.com/) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。 +此 C# SDK 适用于.net framework>2.0版本,基于 [七牛云存储官方API](http://docs.qiniu.com/) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。 - [安装](#install) - [初始化](#setup) diff --git a/Makefile b/Makefile index 7992b4a0..33d742db 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,20 @@ # for travis ci -all: - - xbuild csharp-sdk.sln; - cp Qiniu.Test/bin/Debug/Qiniu.Test.dll bin - cp Qiniu/bin/Debug/Qiniu.dll bin - test: cp tools/Newtonsoft.Json.dll tools/nunit.framework.dll bin #for OS X #export MON_PATH="/Library/Frameworks/Mono.framework/Libraries/mono/4.0/" #mono --debug /Library/Frameworks/Mono.framework/Versions/3.2.0/lib/mono/4.5/nunit-console.exe bin/Qiniu.Test.dll + #for Linux - nunit-console -framework="4.0" bin/Qiniu.Test.dll + #2.0||3.5 + xbuild csharp-sdk.2.0.sln; + cp Qiniu/bin/Debug/2.0/Qiniu.2.0.dll bin/ + cp Qiniu.Test/bin/Debug/2.0/Qiniu.Test.dll bin/Qiniu.2.0.Test.dll + nunit-console bin/Qiniu.2.0.Test.dll + + #4.0 + xbuild csharp-sdk.4.0.sln; + cp Qiniu/bin/Debug/4.0/Qiniu.4.0.dll bin/ + cp Qiniu.Test/bin/Debug/4.0/Qiniu.Test.dll bin/Qiniu.4.0.Test.dll + nunit-console bin/Qiniu.4.0.Test.dll diff --git a/Qiniu.Test/Auth/PutPolicy.cs b/Qiniu.Test/Auth/PutPolicy.cs index 774f04ff..3ea4222f 100644 --- a/Qiniu.Test/Auth/PutPolicy.cs +++ b/Qiniu.Test/Auth/PutPolicy.cs @@ -22,7 +22,7 @@ public class GetPolicyTest:QiniuTestBase public void MakeRequestTest() { string actual; - FileOpUrl = "http://icattlecoder-private.qiniudn.com/img.jpg?download/avialkjdf" + "橛苛要工苛".ToUrlEncode() ; + FileOpUrl = "http://icattlecoder-private.qiniudn.com/img.jpg?download/avialkjdf" + StringEx.ToUrlEncode("橛苛要工苛") ; actual = GetPolicy.MakeRequest(FileOpUrl); //System.Diagnostics.Process.Start(actual); diff --git a/Qiniu.Test/IO/IOClientTest.cs b/Qiniu.Test/IO/IOClientTest.cs index 13198c26..decd1a06 100644 --- a/Qiniu.Test/IO/IOClientTest.cs +++ b/Qiniu.Test/IO/IOClientTest.cs @@ -119,30 +119,32 @@ public void PutFileWithoutKeyTest() //target.PutFile("error", "error", "error", null); Assert.IsTrue (ret.OK, "PutFileTest Failure"); - } - [Test] - public void PutTest() - { - IOClient target = new IOClient(); - string key = NewKey; - PrintLn(key); - PutExtra extra = new PutExtra(); // TODO: 初始化为适当的值 - extra.MimeType = "text/plain"; - extra.Crc32 = 123; - extra.CheckCrc = CheckCrcType.CHECK; - extra.Params = new System.Collections.Generic.Dictionary(); - PutPolicy put = new PutPolicy(Bucket); - target.PutFinished += new EventHandler ((o,e) => { - if (e.OK) { - RSHelper.RSDel (Bucket, key); - } - }); - string token = put.Token (); - PutRet ret = target.Put(put.Token(), key, "Hello, Qiniu Cloud!".ToStream(), extra); - - Assert.IsTrue(ret.OK, "PutFileTest Failure"); - - } + } + [Test] + public void PutTest() + { + IOClient target = new IOClient(); + string key = NewKey; + PrintLn(key); + PutExtra extra = new PutExtra(); // TODO: 初始化为适当的值 + extra.MimeType = "text/plain"; + extra.Crc32 = 123; + extra.CheckCrc = CheckCrcType.CHECK; + extra.Params = new System.Collections.Generic.Dictionary(); + PutPolicy put = new PutPolicy(Bucket); + target.PutFinished += new EventHandler((o, e) => + { + if (e.OK) + { + RSHelper.RSDel(Bucket, key); + } + }); + string token = put.Token(); + PutRet ret = target.Put(put.Token(), key, StreamEx.ToStream("Hello, Qiniu Cloud!"), extra); + + Assert.IsTrue(ret.OK, "PutFileTest Failure"); + + } [Test] public void PutWithoutKeyTest() { diff --git a/Qiniu.Test/Qiniu.2.0.Test.csproj b/Qiniu.Test/Qiniu.2.0.Test.csproj new file mode 100644 index 00000000..74d84e38 --- /dev/null +++ b/Qiniu.Test/Qiniu.2.0.Test.csproj @@ -0,0 +1,64 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {95DC2A77-2344-4315-9F6F-334CC928459C} + Library + Qiniu.Test + Qiniu.Test + v2.0 + + + + true + full + false + bin\Debug\2.0\ + DEBUG;NET20 + prompt + 4 + false + + + full + true + bin\Release\4.0\ + prompt + 4 + false + + + + + ..\tools\nunit.framework.dll + + + + + + + + + + + + + + + + + + + + + + + + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} + Qiniu.2.0 + + + \ No newline at end of file diff --git a/Qiniu.Test/Qiniu.Test.csproj b/Qiniu.Test/Qiniu.4.0.Test.csproj similarity index 83% rename from Qiniu.Test/Qiniu.Test.csproj rename to Qiniu.Test/Qiniu.4.0.Test.csproj index e0237a85..e2117e8c 100644 --- a/Qiniu.Test/Qiniu.Test.csproj +++ b/Qiniu.Test/Qiniu.4.0.Test.csproj @@ -1,72 +1,63 @@ - - - - Debug - AnyCPU - 10.0.0 - 2.0 - {95DC2A77-2344-4315-9F6F-334CC928459C} - Library - Qiniu.Test - Qiniu.Test - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - full - true - bin\Release - prompt - 4 - false - - - - - ..\tools\nunit.framework.dll - - - - - - - - - - - - - - - - - - - - - - - - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} - Qiniu - False - - - - - - - - - - - - + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {95DC2A77-2344-4315-9F6F-334CC928459C} + Library + Qiniu.Test + Qiniu.Test + + + true + full + false + bin\Debug\4.0\ + DEBUG; + prompt + 4 + false + + + full + true + bin\Release\4.0\ + prompt + 4 + false + + + + + ..\tools\nunit.framework.dll + + + + + + + + + + + + + + + + + + + + + + + + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} + Qiniu.4.0 + + + + diff --git a/Qiniu.Test/TestHelper/RSHelper.cs b/Qiniu.Test/TestHelper/RSHelper.cs index f8163d37..7f657859 100644 --- a/Qiniu.Test/TestHelper/RSHelper.cs +++ b/Qiniu.Test/TestHelper/RSHelper.cs @@ -31,7 +31,7 @@ public static List RSPut(string bucket,int num) List newKeys=new List(); for (int i=0; i - /// 七牛提供的公钥,用于识别用户 - /// - public static string ACCESS_KEY = ""; - /// - /// 七牛提供的秘钥,不要在客户端初始化该变量 - /// - public static string SECRET_KEY = ""; - #endregion - #region 七牛服务器地址 - /// - /// 七牛资源管理服务器地址 - /// - public static string RS_HOST = "http://rs.Qbox.me"; - /// - /// 七牛资源上传服务器地址. - /// - public static string UP_HOST = "http://up.qiniu.com"; - /// - /// 七牛资源列表服务器地址. - /// - public static string RSF_HOST = "http://rsf.Qbox.me"; - - public static string PREFETCH_HOST = "http://iovip.qbox.me"; - #endregion - /// - /// 七牛SDK对所有的字节编码采用utf-8形式 . - /// - public static Encoding Encoding = Encoding.UTF8; - - /// - /// 初始化七牛帐户、请求地址等信息,不应在客户端调用。 - /// - public static void Init () - { - USER_AGENT = System.Configuration.ConfigurationManager.AppSettings ["USER_AGENT"]; - ACCESS_KEY = System.Configuration.ConfigurationManager.AppSettings ["ACCESS_KEY"]; - SECRET_KEY = System.Configuration.ConfigurationManager.AppSettings ["SECRET_KEY"]; - RS_HOST = System.Configuration.ConfigurationManager.AppSettings ["RS_HOST"]; - UP_HOST = System.Configuration.ConfigurationManager.AppSettings ["UP_HOST"]; - RSF_HOST = System.Configuration.ConfigurationManager.AppSettings ["RSF_HOST"]; - PREFETCH_HOST = System.Configuration.ConfigurationManager.AppSettings ["PREFETCH_HOST"]; - } - } -} +using System; +using System.Text; + +namespace Qiniu.Conf +{ + public class Config + { + public static string USER_AGENT = "qiniu csharp-sdk v6.0.0"; + #region 帐户信息 + /// + /// 七牛提供的公钥,用于识别用户 + /// + public static string ACCESS_KEY = ""; + /// + /// 七牛提供的秘钥,不要在客户端初始化该变量 + /// + public static string SECRET_KEY = ""; + #endregion + #region 七牛服务器地址 + /// + /// 七牛资源管理服务器地址 + /// + public static string RS_HOST = "http://rs.Qbox.me"; + /// + /// 七牛资源上传服务器地址. + /// + public static string UP_HOST = "http://up.qiniu.com"; + /// + /// 七牛资源列表服务器地址. + /// + public static string RSF_HOST = "http://rsf.Qbox.me"; + + public static string PREFETCH_HOST = "http://iovip.qbox.me"; + + public static string API_HOST = "http://api.qiniu.com"; + #endregion + /// + /// 七牛SDK对所有的字节编码采用utf-8形式 . + /// + public static Encoding Encoding = Encoding.UTF8; + + /// + /// 初始化七牛帐户、请求地址等信息,不应在客户端调用。 + /// + public static void Init() + { + USER_AGENT = System.Configuration.ConfigurationManager.AppSettings["USER_AGENT"]; + ACCESS_KEY = System.Configuration.ConfigurationManager.AppSettings["ACCESS_KEY"]; + SECRET_KEY = System.Configuration.ConfigurationManager.AppSettings["SECRET_KEY"]; + RS_HOST = System.Configuration.ConfigurationManager.AppSettings["RS_HOST"]; + UP_HOST = System.Configuration.ConfigurationManager.AppSettings["UP_HOST"]; + RSF_HOST = System.Configuration.ConfigurationManager.AppSettings["RSF_HOST"]; + PREFETCH_HOST = System.Configuration.ConfigurationManager.AppSettings["PREFETCH_HOST"]; + } + } +} diff --git a/Qiniu/FileOp/ImageInfoRet.cs b/Qiniu/FileOp/ImageInfoRet.cs index 97c5a6da..0d071061 100644 --- a/Qiniu/FileOp/ImageInfoRet.cs +++ b/Qiniu/FileOp/ImageInfoRet.cs @@ -1,49 +1,77 @@ -using System; -using System.Collections.Generic; -using Qiniu.RPC; -using Newtonsoft.Json; - -namespace Qiniu.FileOp -{ - public class ImageInfoRet : CallRet - { - public int Width { get; private set; } - - public int Height { get; private set; } - - public string Format { get; private set; } - - public string ColorModel { get; private set; } - - public ImageInfoRet (CallRet ret) - : base(ret) - { - if (!String.IsNullOrEmpty (Response)) { - try { - Unmarshal (Response); - } catch (Exception e) { - Console.WriteLine (e.ToString ()); - this.Exception = e; - } - } - } - - private void Unmarshal (string json) - { - var dics = JsonConvert.DeserializeObject> (json); - dynamic tmp; - if (dics.TryGetValue ("format", out tmp)) { - Format = (string)tmp; - } - if (dics.TryGetValue ("width", out tmp)) { - Width = (int)tmp; - } - if (dics.TryGetValue ("height", out tmp)) { - Height = (int)tmp; - } - if (dics.TryGetValue ("colorModel", out tmp)) { - ColorModel = (string)tmp; - } - } - } +using System; +using System.Collections.Generic; +using Qiniu.RPC; +using Newtonsoft.Json; + +namespace Qiniu.FileOp +{ + /// + /// Image Info + /// + public class ImageInfoRet : CallRet + { + /// + /// Width + /// + public int Width { get; private set; } + + /// + /// Height + /// + public int Height { get; private set; } + + /// + /// Format + /// + public string Format { get; private set; } + + /// + /// Color Model + /// + public string ColorModel { get; private set; } + + /// + /// construct + /// + /// + public ImageInfoRet(CallRet ret) + : base(ret) + { + if (!String.IsNullOrEmpty(Response)) + { + try + { + Unmarshal(Response); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + this.Exception = e; + } + } + } + + private void Unmarshal(string json) + { + Dictionary dics = JsonConvert.DeserializeObject>(json); + object tmp; + if (dics.TryGetValue("format", out tmp)) + { + this.Format = (string)tmp; + } + if (dics.TryGetValue("colorModel", out tmp)) + { + this.ColorModel = (string)tmp; + } + if (dics.TryGetValue("width", out tmp)) + { + this.Width = Convert.ToInt32(tmp); + } + if (dics.TryGetValue("height", out tmp)) + { + this.Height = Convert.ToInt32(tmp); + } + + } + } } diff --git a/Qiniu/FileOp/ImageWaterMarker.cs b/Qiniu/FileOp/ImageWaterMarker.cs index 8d25520c..c89d80fe 100644 --- a/Qiniu/FileOp/ImageWaterMarker.cs +++ b/Qiniu/FileOp/ImageWaterMarker.cs @@ -21,7 +21,7 @@ public override string MakeRequest (string url) if (string.IsNullOrEmpty (imageUrl)) { throw new Exception ("Water Marker Image Url Error"); } - sb.Append ("/image/" + imageUrl.ToBase64URLSafe ()); + sb.Append ("/image/" + Base64URLSafe.ToBase64URLSafe(imageUrl)); sb.Append ("/dissolve/" + dissolve); sb.Append ("/gravity/" + Gravitys [(int)gravity]); sb.Append ("/dx/" + dx); diff --git a/Qiniu/FileOp/TextWaterMarker.cs b/Qiniu/FileOp/TextWaterMarker.cs index ca932cf3..dcfb128e 100644 --- a/Qiniu/FileOp/TextWaterMarker.cs +++ b/Qiniu/FileOp/TextWaterMarker.cs @@ -1,48 +1,55 @@ using System; using System.Text; -using Qiniu.Util; - -namespace Qiniu.FileOp -{ - public class TextWaterMarker:WaterMarker - { - public string text; - private string fontName; - private int fontSize; - private string color; - - public TextWaterMarker (string text, string fontname = "", string color = "", int fontsize = 0, int dissolve = 50, MarkerGravity gravity = MarkerGravity.SouthEast, int dx = 10, int dy = 10) - : base(dissolve,gravity, dx, dy) - { - this.text = text; - this.fontName = fontname; - this.fontSize = fontsize; - this.color = color; - } - - public override string MakeRequest (string url) - { - StringBuilder sb = new StringBuilder (); - sb.Append (string.Format ("{0}?watermark/{1}", url, 2)); - if (string.IsNullOrEmpty (text)) { - throw new Exception ("No Text To Draw"); - } - sb.Append ("/text/" + text.ToBase64URLSafe ()); - - if (!string.IsNullOrEmpty (fontName)) { - sb.Append ("/font/" + fontName.ToBase64URLSafe ()); - } - if (fontSize > 0) { - sb.Append ("/fontsize/" + fontSize); - } - if (!string.IsNullOrEmpty (color)) { - sb.Append ("/fill/" + color.ToBase64URLSafe ()); - } - sb.Append ("/dissolve/" + dissolve); - sb.Append ("/gravity/" + Gravitys [(int)gravity]); - sb.Append ("/dx/" + dx); - sb.Append ("/dy/" + dy); - return sb.ToString (); - } - } +using Qiniu.Util; + +namespace Qiniu.FileOp +{ + /// + /// + /// + public class TextWaterMarker : WaterMarker + { + private string text; + private string fontName; + private int fontSize; + private string color; + + public TextWaterMarker(string text, string fontname = "", string color = "", int fontsize = 0, int dissolve = 50, MarkerGravity gravity = MarkerGravity.SouthEast, int dx = 10, int dy = 10) + : base(dissolve, gravity, dx, dy) + { + this.text = text; + this.fontName = fontname; + this.fontSize = fontsize; + this.color = color; + } + + public override string MakeRequest(string url) + { + StringBuilder sb = new StringBuilder(); + sb.Append(string.Format("{0}?watermark/{1}", url, 2)); + if (string.IsNullOrEmpty(text)) + { + throw new Exception("No Text To Draw"); + } + sb.Append("/text/" + Base64URLSafe.ToBase64URLSafe(text)); + + if (!string.IsNullOrEmpty(fontName)) + { + sb.Append("/font/" + Base64URLSafe.ToBase64URLSafe(fontName)); + } + if (fontSize > 0) + { + sb.Append("/fontsize/" + fontSize); + } + if (!string.IsNullOrEmpty(color)) + { + sb.Append("/fill/" + Base64URLSafe.ToBase64URLSafe(color)); + } + sb.Append("/dissolve/" + dissolve); + sb.Append("/gravity/" + Gravitys[(int)gravity]); + sb.Append("/dx/" + dx); + sb.Append("/dy/" + dy); + return sb.ToString(); + } + } } diff --git a/Qiniu/IO/PutRet.cs b/Qiniu/IO/PutRet.cs index 6ca774b5..e218c522 100644 --- a/Qiniu/IO/PutRet.cs +++ b/Qiniu/IO/PutRet.cs @@ -28,20 +28,23 @@ public PutRet (CallRet ret) this.Exception = e; } } - } - - private void Unmarshal (string json) - { - try { - var dict = JsonConvert.DeserializeObject> (json); - object tmp; - if (dict.TryGetValue ("hash", out tmp)) - Hash = (string)dict ["hash"]; - if (dict.TryGetValue ("key", out tmp)) - key = (string)dict ["key"]; - } catch (Exception e) { - throw e; - } - } + } + + private void Unmarshal(string json) + { + try + { + Dictionary dict = JsonConvert.DeserializeObject>(json); + object tmp; + if (dict.TryGetValue("hash", out tmp)) + Hash = (string)tmp; + if (dict.TryGetValue("key", out tmp)) + key = (string)tmp; + } + catch (Exception e) + { + throw e; + } + } } } diff --git a/Qiniu/IO/Resumable/ResumablePut.cs b/Qiniu/IO/Resumable/ResumablePut.cs index d5c4b59a..22893e0a 100644 --- a/Qiniu/IO/Resumable/ResumablePut.cs +++ b/Qiniu/IO/Resumable/ResumablePut.cs @@ -1,250 +1,304 @@ using System; using System.IO; using System.Text; +#if NET40 using System.Threading.Tasks; +#endif using Qiniu.Auth; using Qiniu.Conf; using Qiniu.RPC; using Qiniu.RS; -using Qiniu.Util; - -namespace Qiniu.IO.Resumable -{ - /// - /// 异步并行断点上传类 - /// - public class ResumablePut - { - private const int blockBits = 22; - private const int blockMashk = (1 << blockBits) - 1; - private static int BLOCKSIZE = 4 * 1024 * 1024; - private const string UNDEFINED_KEY = "?"; - - #region 记录总文件大小,用于计算上传百分比 - - private long fsize; - private float chunks; - private float uploadedChunks = 0; - - #endregion - - /// - /// 上传完成事件 - /// - public event EventHandler PutFinished; - /// - /// 上传Failure事件 - /// - public event EventHandler PutFailure; - /// - /// 进度提示事件 - /// - public event Action Progress; - - Settings putSetting; - - /// - /// 上传设置 - /// - public Settings PutSetting { - get { return putSetting; } - set { putSetting = value; } - } - - ResumablePutExtra extra; - - /// - /// PutExtra - /// - public ResumablePutExtra Extra { - get { return extra; } - set { extra = value; } - } - - /// - /// 断点续传类 - /// - /// - /// - public ResumablePut (Settings putSetting, ResumablePutExtra extra) - { - extra.chunkSize = putSetting.ChunkSize; - this.putSetting = putSetting; - this.extra = extra; - } - - /// - /// 上传文件 - /// - /// 上传Token - /// key - /// 本地文件名 - public CallRet PutFile (string upToken, string localFile, string key) - { - PutAuthClient client = new PutAuthClient (upToken); - using (FileStream fs = File.OpenRead(localFile)) { - int block_cnt = block_count (fs.Length); - fsize = fs.Length; - chunks = fsize / extra.chunkSize + 1; - extra.Progresses = new BlkputRet[block_cnt]; - //并行上传 - Parallel.For (0, block_cnt, (i) => { - int readLen = BLOCKSIZE; - if ((i + 1) * BLOCKSIZE > fsize) - readLen = (int)(fsize - i * BLOCKSIZE); - byte[] byteBuf = new byte[readLen]; - lock (fs) { - fs.Seek (i * BLOCKSIZE, SeekOrigin.Begin); - fs.Read (byteBuf, 0, readLen); - } - BlkputRet blkRet = ResumableBlockPut (client, byteBuf, i, readLen); - - if (blkRet == null) { - extra.OnNotifyErr (new PutNotifyErrorEvent (i, readLen, "Make Block Error")); - } else { - extra.OnNotify (new PutNotifyEvent (i, readLen, extra.Progresses [i])); - } - - }); - if (string.IsNullOrEmpty (key)) { - key = UNDEFINED_KEY; - } - CallRet ret = Mkfile (client, key, fs.Length); - if (ret.OK) { - if (Progress != null) { - Progress (1.0f); - } - if (PutFinished != null) { - PutFinished (this, ret); - } - } else { - if (PutFailure != null) { - PutFailure (this, ret); - } - } - return ret; - } - } - - /// - /// 百分比进度提示 - /// - private void progress () - { - uploadedChunks++; - if (Progress != null) { - Progress ((float)uploadedChunks / chunks); - } - } - - private BlkputRet ResumableBlockPut (Client client, byte[] body, int blkIdex, int blkSize) - { - int bodyLength; - int chunkSize = extra.chunkSize; - #region Mkblock - if (extra.Progresses [blkIdex] == null) { - bodyLength = chunkSize < blkSize ? chunkSize : blkSize; - byte[] firstChunk = new byte[bodyLength]; - Array.Copy (body, 0, firstChunk, 0, bodyLength); - uint crc32 = CRC32.CheckSumBytes (firstChunk); - for (int i = 0; i < putSetting.TryTimes; i++) { - extra.Progresses [blkIdex] = Mkblock (client, firstChunk, body.Length); - if (extra.Progresses [blkIdex] == null || crc32 != extra.Progresses [blkIdex].crc32) { - if (i == (putSetting.TryTimes - 1)) { - return null; - } - continue; - } else { - progress (); - break; - } - } - } - #endregion - - #region PutBlock - while (extra.Progresses [blkIdex].offset < blkSize) { - bodyLength = (chunkSize < (blkSize - extra.Progresses [blkIdex].offset)) ? chunkSize : (int)(blkSize - extra.Progresses [blkIdex].offset); - byte[] chunk = new byte[bodyLength]; - Array.Copy (body, extra.Progresses [blkIdex].offset, chunk, 0, bodyLength); - for (int i = 0; i < putSetting.TryTimes; i++) { - extra.Progresses [blkIdex] = BlockPut (client, extra.Progresses [blkIdex], new MemoryStream (chunk), bodyLength); - if (extra.Progresses [blkIdex] == null) { - if (i == (putSetting.TryTimes - 1)) { - return null; - } - continue; - } else { - uploadedChunks++; - if (Progress != null) { - Progress ((float)uploadedChunks / chunks); - } - break; - } - } - } - #endregion - return extra.Progresses [blkIdex]; - } - - private BlkputRet Mkblock (Client client, byte[] firstChunk, long blkSize) - { - string url = string.Format ("{0}/mkblk/{1}", Config.UP_HOST, blkSize); - CallRet callRet = client.CallWithBinary (url, "application/octet-stream", new MemoryStream (firstChunk), firstChunk.Length); - if (callRet.OK) { - return callRet.Response.ToObject (); - } - return null; - } - - private BlkputRet BlockPut (Client client, BlkputRet ret, Stream body, long length) - { - string url = string.Format ("{0}/bput/{1}/{2}", Config.UP_HOST, ret.ctx, ret.offset); - CallRet callRet = client.CallWithBinary (url, "application/octet-stream", body, length); - if (callRet.OK) { - return callRet.Response.ToObject (); - } - return null; - } - - private CallRet Mkfile (Client client, string key, long fsize) - { - StringBuilder urlBuilder = new StringBuilder (); - urlBuilder.AppendFormat ("{0}/mkfile/{1}", Config.UP_HOST, fsize); - if (key != null) { - urlBuilder.AppendFormat ("/key/{0}",key.ToBase64URLSafe ()); - } - if (!string.IsNullOrEmpty (extra.MimeType)) { - urlBuilder.AppendFormat ("/mimeType/{0}", extra.MimeType.ToBase64URLSafe ()); - } - if (!string.IsNullOrEmpty (extra.CustomMeta)) { - urlBuilder.AppendFormat ("/meta/{0}", extra.CustomMeta.ToBase64URLSafe ()); - } - if (extra.CallbackParams != null && extra.CallbackParams.Count > 0) { - StringBuilder sb = new StringBuilder (); - foreach (string _key in extra.CallbackParams.Keys) { - sb.AppendFormat ("/{0}/{1}", _key, extra.CallbackParams [_key].ToBase64URLSafe ()); - } - urlBuilder.Append (sb.ToString ()); - } - - int proCount = extra.Progresses.Length; - using (Stream body = new MemoryStream()) { - for (int i = 0; i < proCount; i++) { - byte[] bctx = Encoding.ASCII.GetBytes (extra.Progresses [i].ctx); - body.Write (bctx, 0, bctx.Length); - if (i != proCount - 1) { - body.WriteByte ((byte)','); - } - } - body.Seek (0, SeekOrigin.Begin); - return client.CallWithBinary (urlBuilder.ToString (), "text/plain", body, body.Length); - } - } - - private int block_count (long fsize) - { - return (int)((fsize + blockMashk) >> blockBits); - } - } +using Qiniu.Util; + +namespace Qiniu.IO.Resumable +{ + /// + /// 异步并行断点上传类 + /// + public class ResumablePut + { + private const int blockBits = 22; + private const int blockMashk = (1 << blockBits) - 1; + private static int BLOCKSIZE = 4 * 1024 * 1024; + + #region 记录总文件大小,用于计算上传百分比 + + private long fsize; + private float chunks; + private float uploadedChunks = 0; + + #endregion + + /// + /// 上传完成事件 + /// + public event EventHandler PutFinished; + /// + /// 上传Failure事件 + /// + public event EventHandler PutFailure; + /// + /// 进度提示事件 + /// + public event Action Progress; + + Settings putSetting; + + /// + /// 上传设置 + /// + public Settings PutSetting + { + get { return putSetting; } + set { putSetting = value; } + } + + ResumablePutExtra extra; + + /// + /// PutExtra + /// + public ResumablePutExtra Extra + { + get { return extra; } + set { extra = value; } + } + + /// + /// 断点续传类 + /// + /// + /// + public ResumablePut(Settings putSetting, ResumablePutExtra extra) + { + extra.chunkSize = putSetting.ChunkSize; + this.putSetting = putSetting; + this.extra = extra; + } + + /// + /// 上传文件 + /// + /// 上传Token + /// key + /// 本地文件名 + public CallRet PutFile(string upToken, string localFile, string key) + { + if (!File.Exists(localFile)) + { + throw new Exception(string.Format("{0} does not exist", localFile)); + } + PutAuthClient client = new PutAuthClient(upToken); + CallRet ret; + using (FileStream fs = File.OpenRead(localFile)) + { + int block_cnt = block_count(fs.Length); + fsize = fs.Length; + chunks = fsize / extra.chunkSize + 1; + extra.Progresses = new BlkputRet[block_cnt]; + //并行上传 +#if NET35||NET20 + for (int i = 0; i < block_cnt; i++) + { +#elif NET40 + Parallel.For(0, block_cnt, (i) =>{ +#endif + + int readLen = BLOCKSIZE; + if ((i + 1) * BLOCKSIZE > fsize) + readLen = (int)(fsize - i * BLOCKSIZE); + byte[] byteBuf = new byte[readLen]; +#if NET40 + lock (fs) + { +#endif + fs.Seek(i * BLOCKSIZE, SeekOrigin.Begin); + fs.Read(byteBuf, 0, readLen); +#if NET40 + } +#endif + //并行上传BLOCK + BlkputRet blkRet = ResumableBlockPut(client, byteBuf, i, readLen); + if (blkRet == null) + { + extra.OnNotifyErr(new PutNotifyErrorEvent(i, readLen, "Make Block Error")); + } + else + { + extra.OnNotify(new PutNotifyEvent(i, readLen, extra.Progresses[i])); + } +#if NET35||NET20 + } +#elif NET40 + }); +#endif + ret = Mkfile(client, key, fs.Length); + } + if (ret.OK) + { + if (Progress != null) + { + Progress(1.0f); + } + if (PutFinished != null) + { + PutFinished(this, ret); + } + } + else + { + if (PutFailure != null) + { + PutFailure(this, ret); + } + } + return ret; + } + + + /// + /// 百分比进度提示 + /// + private void progress() + { + uploadedChunks++; + if (Progress != null) + { + Progress((float)uploadedChunks / chunks); + } + } + + private BlkputRet ResumableBlockPut(Client client, byte[] body, int blkIdex, int blkSize) + { + int bodyLength; + int chunkSize = extra.chunkSize; + #region Mkblock + if (extra.Progresses[blkIdex] == null) + { + bodyLength = chunkSize < blkSize ? chunkSize : blkSize; + byte[] firstChunk = new byte[bodyLength]; + Array.Copy(body, 0, firstChunk, 0, bodyLength); + uint crc32 = CRC32.CheckSumBytes(firstChunk); + for (int i = 0; i < putSetting.TryTimes; i++) + { + extra.Progresses[blkIdex] = Mkblock(client, firstChunk, body.Length); + if (extra.Progresses[blkIdex] == null || crc32 != extra.Progresses[blkIdex].crc32) + { + if (i == (putSetting.TryTimes - 1)) + { + return null; + } + continue; + } + else + { + progress(); + break; + } + } + } + #endregion + + #region PutBlock + while (extra.Progresses[blkIdex].offset < blkSize) + { + bodyLength = (chunkSize < (blkSize - extra.Progresses[blkIdex].offset)) ? chunkSize : (int)(blkSize - extra.Progresses[blkIdex].offset); + byte[] chunk = new byte[bodyLength]; + Array.Copy(body, extra.Progresses[blkIdex].offset, chunk, 0, bodyLength); + for (int i = 0; i < putSetting.TryTimes; i++) + { + extra.Progresses[blkIdex] = BlockPut(client, extra.Progresses[blkIdex], new MemoryStream(chunk), bodyLength); + if (extra.Progresses[blkIdex] == null) + { + if (i == (putSetting.TryTimes - 1)) + { + return null; + } + continue; + } + else + { + uploadedChunks++; + if (Progress != null) + { + Progress((float)uploadedChunks / chunks); + } + break; + } + } + } + #endregion + return extra.Progresses[blkIdex]; + } + + private BlkputRet Mkblock(Client client, byte[] firstChunk, long blkSize) + { + string url = string.Format("{0}/mkblk/{1}", Config.UP_HOST, blkSize); + CallRet callRet = client.CallWithBinary(url, "application/octet-stream", new MemoryStream(firstChunk), firstChunk.Length); + if (callRet.OK) + { + return QiniuJsonHelper.ToObject(callRet.Response); + } + return null; + } + + private BlkputRet BlockPut(Client client, BlkputRet ret, Stream body, long length) + { + string url = string.Format("{0}/bput/{1}/{2}", Config.UP_HOST, ret.ctx, ret.offset); + CallRet callRet = client.CallWithBinary(url, "application/octet-stream", body, length); + if (callRet.OK) + { + return QiniuJsonHelper.ToObject(callRet.Response); + } + return null; + } + + private CallRet Mkfile(Client client, string key, long fsize) + { + StringBuilder urlBuilder = new StringBuilder(); + urlBuilder.AppendFormat("{0}/mkfile/{1}", Config.UP_HOST, fsize); + if (key != null) + { + urlBuilder.AppendFormat("/key/{0}", Base64URLSafe.ToBase64URLSafe(key)); + } + if (!string.IsNullOrEmpty(extra.MimeType)) + { + urlBuilder.AppendFormat("/mimeType/{0}", Base64URLSafe.ToBase64URLSafe(extra.MimeType)); + } + if (!string.IsNullOrEmpty(extra.CustomMeta)) + { + urlBuilder.AppendFormat("/meta/{0}", Base64URLSafe.ToBase64URLSafe(extra.CustomMeta)); + } + if (extra.CallbackParams != null && extra.CallbackParams.Count > 0) + { + StringBuilder sb = new StringBuilder(); + foreach (string _key in extra.CallbackParams.Keys) + { + sb.AppendFormat("/{0}/{1}", _key, Base64URLSafe.ToBase64URLSafe(extra.CallbackParams[_key])); + } + urlBuilder.Append(sb.ToString()); + } + + int proCount = extra.Progresses.Length; + using (Stream body = new MemoryStream()) + { + for (int i = 0; i < proCount; i++) + { + byte[] bctx = Encoding.ASCII.GetBytes(extra.Progresses[i].ctx); + body.Write(bctx, 0, bctx.Length); + if (i != proCount - 1) + { + body.WriteByte((byte)','); + } + } + body.Seek(0, SeekOrigin.Begin); + return client.CallWithBinary(urlBuilder.ToString(), "text/plain", body, body.Length); + } + } + + private int block_count(long fsize) + { + return (int)((fsize + blockMashk) >> blockBits); + } + } } diff --git a/Qiniu/IO/Resumable/Settings.cs b/Qiniu/IO/Resumable/Settings.cs index 8bffe436..63331210 100644 --- a/Qiniu/IO/Resumable/Settings.cs +++ b/Qiniu/IO/Resumable/Settings.cs @@ -9,7 +9,7 @@ public class Settings int chunkSize; /// - /// chunk大小,默认为256kb + /// chunk大小,默认为4MB; /// public int ChunkSize { get { return chunkSize; } @@ -29,9 +29,9 @@ public int TryTimes { /// /// 构造函数 /// - /// chunk大小,默认为256kb + /// chunk大小,默认为4MB /// 失败重试次数,默认为3 - public Settings (int chunkSize=1 << 18, int tryTimes=3) + public Settings (int chunkSize=1 << 22, int tryTimes=3) { this.chunkSize = chunkSize; this.tryTimes = tryTimes; diff --git a/Qiniu/Qiniu.2.0.csproj b/Qiniu/Qiniu.2.0.csproj new file mode 100644 index 00000000..00539836 --- /dev/null +++ b/Qiniu/Qiniu.2.0.csproj @@ -0,0 +1,104 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} + Library + Properties + Qiniu + Qiniu.2.0 + 512 + v2.0 + + + + x86 + true + full + false + bin\Debug\2.0\ + TRACE;DEBUG;NET20 + prompt + 4 + bin\Debug\2.0\Qiniu.XML + + + x86 + pdbonly + true + bin\Release\4.0\ + TRACE + prompt + 4 + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\tools\Newtonsoft.Json.dll + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Qiniu/Qiniu.csproj b/Qiniu/Qiniu.4.0.csproj similarity index 88% rename from Qiniu/Qiniu.csproj rename to Qiniu/Qiniu.4.0.csproj index 75d1a536..1734a9af 100644 --- a/Qiniu/Qiniu.csproj +++ b/Qiniu/Qiniu.4.0.csproj @@ -1,105 +1,105 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} - Library - Properties - Qiniu - Qiniu - 512 - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Qiniu.XML - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\tools\Newtonsoft.Json.dll - - - - - - - - - - - - - - + + + + Debug + x86 + 8.0.30703 + 2.0 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} + Library + Properties + Qiniu + Qiniu.4.0 + 512 + v4.0 + + + + x86 + true + full + false + bin\Debug\4.0\ + TRACE;DEBUG;NET40 + prompt + 4 + bin\Debug\4.0\Qiniu.XML + + + x86 + pdbonly + true + bin\Release\4.0\ + TRACE + prompt + 4 + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\tools\Newtonsoft.Json.dll + + + + + + + + + + + diff --git a/Qiniu/RS/Entry.cs b/Qiniu/RS/Entry.cs index 4c574d44..fb0e454a 100644 --- a/Qiniu/RS/Entry.cs +++ b/Qiniu/RS/Entry.cs @@ -1,76 +1,86 @@ using System; using System.Collections.Generic; using Newtonsoft.Json; -using Qiniu.RPC; - -namespace Qiniu.RS -{ - public class Entry : CallRet - { - /// - /// 文件的Hash值 - /// - /// true if this instance hash; otherwise, false. - public string Hash { get; private set; } - - /// - /// 文件的大小(单位: 字节) - /// - /// The fsize. - public long Fsize { get; private set; } - - /// - /// 文件上传到七牛云的时间(Unix时间戳) - /// - /// The put time. - public long PutTime { get; private set; } - - /// - /// 文件的媒体类型,比如"image/gif" - /// - /// The type of the MIME. - public string MimeType { get; private set; } - - /// - /// Gets the customer. - /// - /// The customer. - public string Customer { get; private set; } - - public Entry (CallRet ret) - : base(ret) - { - if (OK && !string.IsNullOrEmpty (Response)) { - try { - Unmarshal (Response); - } catch (Exception e) { - Console.WriteLine (e.ToString ()); - this.Exception = e; - } - } - } - - private void Unmarshal (string json) - { - var dict = JsonConvert.DeserializeObject> (json); - if (dict != null) { - dynamic tmp; - if (dict.TryGetValue ("hash", out tmp)) { - Hash = (string)tmp; - } - if (dict.TryGetValue ("mimeType", out tmp)) { - MimeType = (string)tmp; - } - if (dict.TryGetValue ("fsize", out tmp)) { - Fsize = (long)tmp; - } - if (dict.TryGetValue ("putTime", out tmp)) { - PutTime = (long)tmp; - } - if (dict.TryGetValue ("customer", out tmp)) { - Customer = (string)tmp; - } - } - } - } +using Qiniu.RPC; + +namespace Qiniu.RS +{ + public class Entry : CallRet + { + /// + /// 文件的Hash值 + /// + /// true if this instance hash; otherwise, false. + public string Hash { get; private set; } + + /// + /// 文件的大小(单位: 字节) + /// + /// The fsize. + public long Fsize { get; private set; } + + /// + /// 文件上传到七牛云的时间(Unix时间戳) + /// + /// The put time. + public long PutTime { get; private set; } + + /// + /// 文件的媒体类型,比如"image/gif" + /// + /// The type of the MIME. + public string MimeType { get; private set; } + + /// + /// Gets the customer. + /// + /// The customer. + public string Customer { get; private set; } + + public Entry(CallRet ret) + : base(ret) + { + if (OK && !string.IsNullOrEmpty(Response)) + { + try + { + Unmarshal(Response); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + this.Exception = e; + } + } + } + + private void Unmarshal(string json) + { + Dictionary dict = JsonConvert.DeserializeObject>(json); + if (dict != null) + { + object tmp; + if (dict.TryGetValue("hash", out tmp)) + { + Hash = (string)tmp; + } + if (dict.TryGetValue("mimeType", out tmp)) + { + MimeType = (string)tmp; + } + if (dict.TryGetValue("fsize", out tmp)) + { + Fsize = Convert.ToInt64(tmp); + } + if (dict.TryGetValue("putTime", out tmp)) + { + PutTime = Convert.ToInt64(tmp); + } + if (dict.TryGetValue("customer", out tmp)) + { + Customer = (string)tmp; + } + } + } + } } diff --git a/Qiniu/RS/GetPolicy.cs b/Qiniu/RS/GetPolicy.cs index ced418ad..a7c28202 100644 --- a/Qiniu/RS/GetPolicy.cs +++ b/Qiniu/RS/GetPolicy.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using Qiniu.Auth.digest; using Qiniu.Conf; @@ -17,7 +16,7 @@ public static string MakeRequest (string baseUrl, UInt32 expires = 3600, Mac mac } UInt32 deadline = (UInt32)((DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000 + expires); - if (baseUrl.Contains ('?')) { + if (baseUrl.Contains ("?")) { baseUrl += "&e="; } else { baseUrl += "?e="; diff --git a/Qiniu/RS/Pfop.cs b/Qiniu/RS/Pfop.cs new file mode 100644 index 00000000..2521d068 --- /dev/null +++ b/Qiniu/RS/Pfop.cs @@ -0,0 +1,123 @@ +using System; +using System.Text; +using Newtonsoft.Json; +using Qiniu.Auth; +using Qiniu.Conf; +using Qiniu.RPC; +using Qiniu.Util; + +namespace Qiniu.RS +{ + /// + /// Persistent identifier. + /// + public class PersistentId + { + public string persistentId; + } + + /// + /// Persitent error. + /// + public class PersitentError + { + public int code; + public string error; + + } + + /// + /// Persistent exception. + /// + public class PersistentException : Exception + { + + private PersitentError error; + + public PersitentError Error + { + get + { + return error; + } + } + + public PersistentException(PersitentError err) + { + this.error = err; + } + } + + /// + /// 对已有资源手动触发持久化 + /// POST /pfop/ HTTP/1.1 + /// Host: api.qiniu.com + /// Content-Type: application/x-www-form-urlencoded + /// Authorization: + /// bucket=&key=&fops=;...¬ifyURL= + /// + public class Pfop : QiniuAuthClient + { + /// + /// 请求持久化 + /// + /// + /// + /// + /// + public string Do(EntryPath entry, string[] fops, Uri notifyURL) + { + if (fops.Length < 1 || entry == null || string.IsNullOrEmpty(entry.Bucket) || notifyURL == null || !notifyURL.IsAbsoluteUri) + { + throw new Exception("params error"); + } + StringBuilder sb = new StringBuilder(); + sb.Append(fops[0]); + + for (int i = 1; i < fops.Length; ++i) + { + sb.Append(";"); + sb.Append(fops[i]); + } + + string body = string.Format("bucket={0}&key={1}&fops={2}¬ifyURL={3}", entry.Bucket, StringEx.ToUrlEncode(entry.Key), sb.ToString(), notifyURL.ToString()); + + CallRet ret = CallWithBinary(Config.API_HOST + "/pfop/", "application/x-www-form-urlencoded",StreamEx.ToStream(body), body.Length); + + if (ret.OK) + { + try + { + PersistentId pid = JsonConvert.DeserializeObject(ret.Response); + return pid.persistentId; + } + catch (Exception e) + { + throw e; + } + } + else + { + throw new Exception(ret.Response); + } + } + + /// + /// Queries the pfop status. + /// + /// The pfop status. + /// Persistent identifier. + public string QueryPfopStatus(string persistentId) + { + CallRet ret = Call(string.Format("{0}/status/get/prefop?id={1}", Config.API_HOST, persistentId)); + if (ret.OK) + { + return ret.Response; + } + else + { + throw new Exception(ret.Response); + } + } + } +} diff --git a/Qiniu/RS/RSClient.cs b/Qiniu/RS/RSClient.cs index 6054aa5c..4d3a1a04 100644 --- a/Qiniu/RS/RSClient.cs +++ b/Qiniu/RS/RSClient.cs @@ -168,12 +168,12 @@ OPS [(int)op], Base64URLSafe.Encode (keys [keys.Length - 1].URISrc), Base64URLSafe.Encode (keys [keys.Length - 1].URIDest)); return sb.Append (litem).ToString (); - } - - private CallRet batch (string requestBody) - { - return CallWithBinary (Conf.Config.RS_HOST + "/batch", "application/x-www-form-urlencoded", requestBody.ToStream (), requestBody.Length); - } + } + + private CallRet batch(string requestBody) + { + return CallWithBinary(Conf.Config.RS_HOST + "/batch", "application/x-www-form-urlencoded", StreamEx.ToStream(requestBody), requestBody.Length); + } /// /// 批操作:文件信息查看 diff --git a/Qiniu/Util/Base64UrlSafe.cs b/Qiniu/Util/Base64UrlSafe.cs index 46459c10..0dcea94d 100644 --- a/Qiniu/Util/Base64UrlSafe.cs +++ b/Qiniu/Util/Base64UrlSafe.cs @@ -20,7 +20,7 @@ public static string Encode (string text) /// /// /// - public static string ToBase64URLSafe (this string str) + public static string ToBase64URLSafe (string str) { return Encode (str); } diff --git a/Qiniu/Util/QiniuJsonHelper.cs b/Qiniu/Util/QiniuJsonHelper.cs index 72aa66c3..c0cdcb7a 100644 --- a/Qiniu/Util/QiniuJsonHelper.cs +++ b/Qiniu/Util/QiniuJsonHelper.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; + namespace Qiniu.Util { public static class QiniuJsonHelper @@ -11,7 +12,7 @@ public static string JsonEncode (object obj) return JsonConvert.SerializeObject (obj, setting); } - public static T ToObject (this string value) + public static T ToObject (string value) { return JsonConvert.DeserializeObject (value); } diff --git a/Qiniu/Util/StreamEx.cs b/Qiniu/Util/StreamEx.cs index c2570786..a4cd037b 100644 --- a/Qiniu/Util/StreamEx.cs +++ b/Qiniu/Util/StreamEx.cs @@ -10,7 +10,7 @@ public static class StreamEx /// /// /// - public static Stream ToStream (this string str) + public static Stream ToStream (string str) { Stream s = new MemoryStream (Conf.Config.Encoding.GetBytes (str)); return s; diff --git a/Qiniu/Util/StringEx.cs b/Qiniu/Util/StringEx.cs index 927b378a..4d7bcd13 100644 --- a/Qiniu/Util/StringEx.cs +++ b/Qiniu/Util/StringEx.cs @@ -4,9 +4,17 @@ namespace Qiniu.Util { + /// + /// String辅助函数 + /// public static class StringEx { - public static string ToUrlEncode (this string value) + /// + /// 对字符串进行Url编码 + /// + /// + /// + public static string ToUrlEncode (string value) { return System.Web.HttpUtility.UrlEncode (value); } diff --git a/Qiniu/app.config b/Qiniu/app.config index 683f2a50..4bcf4054 100644 --- a/Qiniu/app.config +++ b/Qiniu/app.config @@ -1,12 +1,13 @@ - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/README.md b/README.md index 7b6d86f4..0c9be7a4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # 关于 -此 C# SDK 适用于 .NET4 及以上版本,基于 [七牛云存储官方API](http://docs.qiniu.com/api/) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。 +此 C# SDK 适用于 .NET2.0 及以上版本,基于 [七牛云存储官方API](http://developer.qiniu.com/docs/v6/api/) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。 ## 使用 diff --git a/bin/Qiniu.4.0.dll b/bin/Qiniu.4.0.dll new file mode 100755 index 00000000..3263456b Binary files /dev/null and b/bin/Qiniu.4.0.dll differ diff --git a/bin/Qiniu.dll b/bin/Qiniu.dll deleted file mode 100755 index 58e95078..00000000 Binary files a/bin/Qiniu.dll and /dev/null differ diff --git a/csharp-sdk.sln b/csharp-sdk.2.0.sln similarity index 92% rename from csharp-sdk.sln rename to csharp-sdk.2.0.sln index a81a6fad..f374e292 100644 --- a/csharp-sdk.sln +++ b/csharp-sdk.2.0.sln @@ -3,11 +3,14 @@ Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SDK", "SDK", "{65603FA4-DDC3-4FD7-ADA3-7BCC2161A247}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu", "Qiniu\Qiniu.csproj", "{AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu", "Qiniu\Qiniu.2.0.csproj", "{AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.Test", "Qiniu.Test\Qiniu.Test.csproj", "{95DC2A77-2344-4315-9F6F-334CC928459C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.Test", "Qiniu.Test\Qiniu.2.0.Test.csproj", "{95DC2A77-2344-4315-9F6F-334CC928459C}" EndProject Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = csharp-sdk.vsmdi + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|Mixed Platforms = Debug|Mixed Platforms @@ -17,6 +20,16 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Any CPU.ActiveCfg = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|x86.ActiveCfg = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|x86.Build.0 = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Any CPU.ActiveCfg = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Mixed Platforms.Build.0 = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|x86.ActiveCfg = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|x86.Build.0 = Release|x86 {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|Any CPU.Build.0 = Debug|Any CPU {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -29,28 +42,15 @@ Global {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|Mixed Platforms.Build.0 = Release|Any CPU {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|x86.ActiveCfg = Release|Any CPU {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|x86.Build.0 = Release|Any CPU - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Any CPU.ActiveCfg = Debug|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|x86.ActiveCfg = Debug|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|x86.Build.0 = Debug|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Any CPU.ActiveCfg = Release|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Mixed Platforms.Build.0 = Release|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|x86.ActiveCfg = Release|x86 - {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} = {65603FA4-DDC3-4FD7-ADA3-7BCC2161A247} {95DC2A77-2344-4315-9F6F-334CC928459C} = {65603FA4-DDC3-4FD7-ADA3-7BCC2161A247} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = Qiniu\Qiniu.csproj - EndGlobalSection - GlobalSection(TestCaseManagementSettings) = postSolution - CategoryFile = csharp-sdk.vsmdi - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE + StartupItem = Qiniu.LocalTest\QiniuLocalTest.csproj EndGlobalSection EndGlobal diff --git a/csharp-sdk.4.0.sln b/csharp-sdk.4.0.sln new file mode 100644 index 00000000..a98455bc --- /dev/null +++ b/csharp-sdk.4.0.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SDK", "SDK", "{65603FA4-DDC3-4FD7-ADA3-7BCC2161A247}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu", "Qiniu\Qiniu.4.0.csproj", "{AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qiniu.Test", "Qiniu.Test\Qiniu.4.0.Test.csproj", "{95DC2A77-2344-4315-9F6F-334CC928459C}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = csharp-sdk.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Any CPU.ActiveCfg = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|x86.ActiveCfg = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Debug|x86.Build.0 = Debug|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Any CPU.ActiveCfg = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|Mixed Platforms.Build.0 = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|x86.ActiveCfg = Release|x86 + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80}.Release|x86.Build.0 = Release|x86 + {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|x86.ActiveCfg = Debug|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Debug|x86.Build.0 = Debug|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|Any CPU.Build.0 = Release|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|x86.ActiveCfg = Release|Any CPU + {95DC2A77-2344-4315-9F6F-334CC928459C}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {AD4EA9D1-11C2-4BF6-8A06-72A966BC1B80} = {65603FA4-DDC3-4FD7-ADA3-7BCC2161A247} + {95DC2A77-2344-4315-9F6F-334CC928459C} = {65603FA4-DDC3-4FD7-ADA3-7BCC2161A247} + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = Qiniu.LocalTest\QiniuLocalTest.csproj + EndGlobalSection +EndGlobal diff --git a/tools/Newtonsoft.Json.dll b/tools/Newtonsoft.Json.dll index 92e36fca..93875d5d 100755 Binary files a/tools/Newtonsoft.Json.dll and b/tools/Newtonsoft.Json.dll differ