zoukankan      html  css  js  c++  java
  • 如何优雅地使用腾讯云COS-.NET篇

    如何优雅地使用腾讯云COS-.NET篇

    代码下载地址 https://github.com/whuanle/txypx20190809

    前提

    创建子账号

    打开 https://console.cloud.tencent.com/cam

    创建子用户,设置子账号策略为 AdministratorAccess ,或者参考https://cloud.tencent.com/document/product/436/11714 ,添加访问 COS 的权限 记录子用户的 账号ID

    切换子用户登录。

    添加 appid 密钥

    打开 https://console.cloud.tencent.com/cam/capi

    新建 API 密钥,记录下 appid,记录 SecretIdSecretKey

    记录 Region

    打开 https://cloud.tencent.com/document/product/436/6224

    可以查询可用区/地域的 region。

    本教程使用 C# 开发。

    一,SDK 和使用

    腾讯云官网提供了 .NET 版本的 对象存储(COS) SDK,并提供使用教程,教程链接:

    https://cloud.tencent.com/document/product/436/32819

    Nuget 搜索 Tencent.QCloud.Cos.Sdk 安装即可。

    using 需引入

    using COSXML;
    using COSXML.Auth;
    using COSXML.Model.Object;
    using COSXML.Model.Bucket;
    using COSXML.CosException;
    using COSXML.Utils;
    using COSXML.Model.Service;
    using COSXML.Transfer;
    using COSXML.Model;
    

    根据官方的教程,很容易编写自己的软件:

    Ctrl + C ,然后 Ctrl + V

    拷贝完毕,大概是这样的

    using System;
    using System.Collections.Generic;
    using System.Text;
    using COSXML;
    using COSXML.Auth;
    using COSXML.Model.Object;
    using COSXML.Model.Bucket;
    using COSXML.CosException;
    using COSXML.Utils;
    using COSXML.Model.Service;
    using COSXML.Transfer;
    using COSXML.Model;
    
    namespace CosTest
    {
        public class CosClient
        {
            CosXmlServer cosXml;
            private readonly string _appid;
            private readonly string _region;
            public CosClient(string appid, string region)
            {
                _appid = appid;
                _region = region;
    
                //初始化 CosXmlConfig 
                //string appid = "100011070645";
                //string region = "ap-guangzhou"; 
                CosXmlConfig config = new CosXmlConfig.Builder()
                    .SetConnectionTimeoutMs(60000)
                    .SetReadWriteTimeoutMs(40000)
                    .IsHttps(true)
                    .SetAppid(appid)
                    .SetRegion(region)
                    .SetDebugLog(true)
                    .Build();
    
                QCloudCredentialProvider cosCredentialProvider = null;
    
                string secretId = "AKID62jALHsVmpfHentPs9E6lBMJ2XnnsTzH"; //"云 API 密钥 SecretId";
                string secretKey = "CC0c1DAtNdfS0IPIvISRFtIUSCUYTAgy"; //"云 API 密钥 SecretKey";
                long durationSecond = 600;  //secretKey 有效时长,单位为 秒
                cosCredentialProvider = new DefaultQCloudCredentialProvider(secretId, secretKey, durationSecond);
    
                //初始化 CosXmlServer
                cosXml = new CosXmlServer(config, cosCredentialProvider);
            }
            public bool CreateBucket(string buketName)
            {
                try
                {
                    string bucket = buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    PutBucketRequest request = new PutBucketRequest(buketName);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //执行请求
                    PutBucketResult result = cosXml.PutBucket(request);
                    //请求成功
                    Console.WriteLine(result.GetResultInfo());
                    return true;
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    //请求失败
                    Console.WriteLine("CosClientException: " + clientEx.Message);
                    return false;
                }
                catch (COSXML.CosException.CosServerException serverEx)
                {
                    //请求失败
                    Console.WriteLine("CosServerException: " + serverEx.GetInfo());
                    return false;
                }
            }
            public bool SelectBucket()
            {
                try
                {
                    GetServiceRequest request = new GetServiceRequest();
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //执行请求
                    GetServiceResult result = cosXml.GetService(request);
                    //请求成功
                    Console.WriteLine(result.GetResultInfo());
                    return true;
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    //请求失败
                    Console.WriteLine("CosClientException: " + clientEx.Message);
                    return false;
                }
                catch (COSXML.CosException.CosServerException serverEx)
                {
                    //请求失败
                    Console.WriteLine("CosServerException: " + serverEx.GetInfo());
                    return false;
                }
            }
    
            public bool Upfile(string buketName, string key, string srcPath)
            {
                try
                {
                    string bucket = buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    PutObjectRequest request = new PutObjectRequest(bucket, key, srcPath);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //设置进度回调
                    request.SetCosProgressCallback(delegate (long completed, long total)
                    {
                        Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
                    });
                    //执行请求
                    PutObjectResult result = cosXml.PutObject(request);
                    //请求成功
                    Console.WriteLine(result.GetResultInfo());
                    return true;
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    //请求失败
                    Console.WriteLine("CosClientException: " + clientEx.Message);
                    return false;
                }
                catch (COSXML.CosException.CosServerException serverEx)
                {
                    //请求失败
                    Console.WriteLine("CosServerException: " + serverEx.GetInfo());
                    return false;
                }
            }
            public void UpBigFile(string buketName, string key, string srcPath)
            {
                string bucket = buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
    
                TransferManager transferManager = new TransferManager(cosXml, new TransferConfig());
                COSXMLUploadTask uploadTask = new COSXMLUploadTask(bucket, null, key);
                uploadTask.SetSrcPath(srcPath);
                uploadTask.progressCallback = delegate (long completed, long total)
                {
                    Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
                };
                uploadTask.successCallback = delegate (CosResult cosResult)
                {
                    COSXML.Transfer.COSXMLUploadTask.UploadTaskResult result = cosResult as COSXML.Transfer.COSXMLUploadTask.UploadTaskResult;
                    Console.WriteLine(result.GetResultInfo());
                };
                uploadTask.failCallback = delegate (CosClientException clientEx, CosServerException serverEx)
                {
                    if (clientEx != null)
                    {
                        Console.WriteLine("CosClientException: " + clientEx.Message);
                    }
                    if (serverEx != null)
                    {
                        Console.WriteLine("CosServerException: " + serverEx.GetInfo());
                    }
                };
                transferManager.Upload(uploadTask);
            }
            public class ResponseModel
            {
                public int Code { get; set; }
                public string Message { get; set; }
                public dynamic Data { get; set; }
            }
            public ResponseModel SelectObjectList(string buketName)
            {
                try
                {
                    string bucket = buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    GetBucketRequest request = new GetBucketRequest(bucket);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //执行请求
                    GetBucketResult result = cosXml.GetBucket(request);
                    //请求成功
                    Console.WriteLine(result.GetResultInfo());
                    return new ResponseModel { Code = 200, Data = result.GetResultInfo() };
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    //请求失败
                    Console.WriteLine("CosClientException: " + clientEx.Message);
                    return new ResponseModel { Code = 200, Data = clientEx.Message };
                }
                catch (COSXML.CosException.CosServerException serverEx)
                {
                    //请求失败
                    Console.WriteLine("CosServerException: " + serverEx.GetInfo());
                    return new ResponseModel { Code = 200, Data = serverEx.Message };
                }
            }
            public bool DownObject(string buketName, string key, string localDir, string localFileName)
            {
                try
                {
                    string bucket = buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //设置进度回调
                    request.SetCosProgressCallback(delegate (long completed, long total)
                    {
                        Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
                    });
                    //执行请求
                    GetObjectResult result = cosXml.GetObject(request);
                    //请求成功
                    Console.WriteLine(result.GetResultInfo());
                    return true;
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    //请求失败
                    Console.WriteLine("CosClientException: " + clientEx.Message);
                    return false;
                }
                catch (COSXML.CosException.CosServerException serverEx)
                {
                    //请求失败
                    Console.WriteLine("CosServerException: " + serverEx.GetInfo());
                    return false;
                }
            }
            public bool DeleteObject(string buketName)
            {
                try
                {
                    string bucket = buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    string key = "exampleobject"; //对象在存储桶中的位置,即称对象键.
                    DeleteObjectRequest request = new DeleteObjectRequest(bucket, key);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //执行请求
                    DeleteObjectResult result = cosXml.DeleteObject(request);
                    //请求成功
                    Console.WriteLine(result.GetResultInfo());
                    return true;
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    //请求失败
                    Console.WriteLine("CosClientException: " + clientEx.Message);
                    return false;
                }
                catch (COSXML.CosException.CosServerException serverEx)
                {
                    //请求失败
                    Console.WriteLine("CosServerException: " + serverEx.GetInfo());
                    return false;
                }
            }
        }
    }
    
    
    

    概览:

    1565341618

    但是大神说,这样不好,程序要高内聚、低耦合,依赖与抽象而不依赖于具体实现。

    那怎么办?只能修改一下。

    二,优化

    1,对象构建器

    对象存储的 SDK 中,有三个重要的对象:

    • CosXmlConfig 提供配置 SDK 接口。
    • QCloudCredentialProvider 提供设置密钥信息接口。
    • CosXmlServer 提供各种 COS API 服务接口。

    但是,初始化和配置对象,过于麻烦,那么我们做一个对象构建器,实现函数式编程和链式语法。

        /// <summary>
        /// 生成Cos客户端工具类
        /// </summary>
        public class CosBuilder
        {
            private CosXmlServer cosXml;
            private string _appid;
            private string _region;
            private CosXmlConfig cosXmlConfig;
            private QCloudCredentialProvider cosCredentialProvider;
            public CosBuilder()
            {
    
            }
    
    
            public CosBuilder SetAccount(string appid, string region)
            {
                _appid = appid;
                _region = region;
                return this;
            }
            public CosBuilder SetCosXmlServer(int ConnectionTimeoutMs = 60000, int ReadWriteTimeoutMs = 40000, bool IsHttps = true, bool SetDebugLog = true)
            {
                cosXmlConfig = new CosXmlConfig.Builder()
                    .SetConnectionTimeoutMs(ConnectionTimeoutMs)
                    .SetReadWriteTimeoutMs(ReadWriteTimeoutMs)
                    .IsHttps(true)
                    .SetAppid(_appid)
                    .SetRegion(_region)
                    .SetDebugLog(true)
                    .Build();
                return this;
            }
            public CosBuilder SetSecret(string secretId, string secretKey, long durationSecond = 600)
            {
    
                cosCredentialProvider = new DefaultQCloudCredentialProvider(secretId, secretKey, durationSecond);
                return this;
            }
            public CosXmlServer Builder()
            {
                //初始化 CosXmlServer
                cosXml = new CosXmlServer(cosXmlConfig, cosCredentialProvider);
                return cosXml;
            }
        }
    

    2,消息响应对象

    为了统一返回消息,创建一个 Response Model 的类。

        /// <summary>
        /// 消息响应
        /// </summary>
        public class ResponseModel
        {
            public int Code { get; set; }
            public string Message { get; set; }
            public dynamic Data { get; set; }
        }
    

    3,接口

    实际上,访问 COS和控制,和存储桶内的操作,是可以分开的。

    访问 COS 可以控制对象存储内的所有东西,但是每个存储桶又是一个独立的对象。

    为了松耦合,我们拆分两个客户端,一个用来管理连接、存储桶等,一个用来管理存储桶内的操作。

    接口如下:

    
        public interface ICosClient
        {
            // 创建存储桶
            Task<ResponseModel> CreateBucket(string buketName);
    
            // 获取存储桶列表
            Task<ResponseModel> SelectBucket(int tokenTome = 600);
        }
        public interface IBucketClient
        {
            // 上传文件
            Task<ResponseModel> UpFile(string key, string srcPath);
    
            // 分块上传大文件
            Task<ResponseModel> UpBigFile(string key, string srcPath, Action<long, long> progressCallback, Action<CosResult> successCallback);
    
            // 查询存储桶的文件列表
            Task<ResponseModel> SelectObjectList();
    
            // 下载文件
            Task<ResponseModel> DownObject(string key, string localDir, string localFileName);
    
            // 删除文件
            Task<ResponseModel> DeleteObject(string buketName);
        }
    

    所有接口功能都使用异步实现。

    4,COS 客户端

    基架代码:

        public class CosClient : ICosClient
        {
            CosXmlServer _cosXml;
            private readonly string _appid;
            private readonly string _region;
            public CosClient(CosXmlServer cosXml)
            {
                _cosXml = cosXml;
            }
    
        }
    

    创建存储桶:

    
            public async Task<ResponseModel> CreateBucket(string buketName)
            {
                try
                {
                    string bucket = buketName + "-" + _appid; 
                    PutBucketRequest request = new PutBucketRequest(bucket);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //执行请求
                    PutBucketResult result = await Task.FromResult(_cosXml.PutBucket(request));
    
                    return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    //请求失败
                    Console.WriteLine();
                    return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
                }
                catch (COSXML.CosException.CosServerException serverEx)
                {
                    return new ResponseModel { Code = 200, Message = "CosServerException: " + serverEx.GetInfo() };
                }
            }
    
       
    

    查询存储桶列表

            public async Task<ResponseModel> SelectBucket(int tokenTome = 600)
            {
                try
                {
                    GetServiceRequest request = new GetServiceRequest();
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), tokenTome);
                    //执行请求
                    GetServiceResult result = await Task.FromResult(_cosXml.GetService(request));
                    return new ResponseModel { Code = 200, Message = "Success", Data = result.GetResultInfo() };
                }
                catch (COSXML.CosException.CosClientException clientEx)
                {
                    return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
                }
                catch (CosServerException serverEx)
                {
                    return new ResponseModel { Code = 0, Message = "CosServerException: " + serverEx.GetInfo() };
                }
            }
    

    5,存储桶操作客户端

    基架代码如下:

        /// <summary>
        /// 存储桶客户端
        /// </summary>
        public class BucketClient : IBucketClient
        {
            private readonly CosXmlServer _cosXml;
            private readonly string _buketName;
            private readonly string _appid;
            public BucketClient(CosXmlServer cosXml, string buketName, string appid)
            {
                _cosXml = cosXml;
                _buketName = buketName;
                _appid = appid;
            }
    
        }
    

    上传对象

            public async Task<ResponseModel> UpFile(string key, string srcPath)
            {
                try
                {
                    string bucket = _buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    PutObjectRequest request = new PutObjectRequest(bucket, key, srcPath);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //设置进度回调
                    request.SetCosProgressCallback(delegate (long completed, long total)
                    {
                        Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
                    });
                    //执行请求
                    PutObjectResult result = await Task.FromResult(_cosXml.PutObject(request));
    
                    return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
                }
                catch (CosClientException clientEx)
                {
                    return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
                }
                catch (CosServerException serverEx)
                {
                    return new ResponseModel { Code = 0, Message = "CosServerException: " + serverEx.GetInfo() };
                }
            }
    

    大文件分块上传

            /// <summary>
            /// 上传大文件、分块上传
            /// </summary>
            /// <param name="key"></param>
            /// <param name="srcPath"></param>
            /// <param name="progressCallback">委托,可用于显示分块信息</param>
            /// <param name="successCallback">委托,当任务成功时回调</param>
            /// <returns></returns>
            public async Task<ResponseModel> UpBigFile(string key, string srcPath, Action<long, long> progressCallback, Action<CosResult> successCallback)
            {
                ResponseModel responseModel = new ResponseModel();
                string bucket = _buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
    
                TransferManager transferManager = new TransferManager(_cosXml, new TransferConfig());
                COSXMLUploadTask uploadTask = new COSXMLUploadTask(bucket, null, key);
                uploadTask.SetSrcPath(srcPath);
                uploadTask.progressCallback = delegate (long completed, long total)
                {
                    progressCallback(completed, total);
                    //Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
                };
                uploadTask.successCallback = delegate (CosResult cosResult)
                {
                    COSXMLUploadTask.UploadTaskResult result = cosResult as COSXMLUploadTask.UploadTaskResult;
                    successCallback(cosResult);
                    responseModel.Code = 200;
                    responseModel.Message = result.GetResultInfo();
                };
                uploadTask.failCallback = delegate (CosClientException clientEx, CosServerException serverEx)
                {
                    if (clientEx != null)
                    {
                        responseModel.Code = 0;
                        responseModel.Message = clientEx.Message;
                    }
                    if (serverEx != null)
                    {
                        responseModel.Code = 0;
                        responseModel.Message = "CosServerException: " + serverEx.GetInfo();
                    }
                };
                await Task.Run(() =>
                {
                    transferManager.Upload(uploadTask);
                });
                return responseModel;
            }
    

    查询对象列表

            public async Task<ResponseModel> SelectObjectList()
            {
                try
                {
                    string bucket = _buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    GetBucketRequest request = new GetBucketRequest(bucket);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //执行请求
                    GetBucketResult result = await Task.FromResult(_cosXml.GetBucket(request));
                    return new ResponseModel { Code = 200, Data = result.GetResultInfo() };
                }
                catch (CosClientException clientEx)
                {
                    return new ResponseModel { Code = 0, Data = "CosClientException: " + clientEx.Message };
                }
                catch (CosServerException serverEx)
                {
                    return new ResponseModel { Code = 0, Data = "CosServerException: " + serverEx.GetInfo() };
                }
            }
    

    下载对象 、删除对象

            public async Task<ResponseModel> DownObject(string key, string localDir, string localFileName)
            {
                try
                {
                    string bucket = _buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //设置进度回调
                    request.SetCosProgressCallback(delegate (long completed, long total)
                    {
                        Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
                    });
                    //执行请求
                    GetObjectResult result = await Task.FromResult(_cosXml.GetObject(request));
    
                    return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
                }
                catch (CosClientException clientEx)
                {
                    return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
                }
                catch (CosServerException serverEx)
                {
                    return new ResponseModel { Code = 0, Message = serverEx.GetInfo() };
                }
            }
            public async Task<ResponseModel> DeleteObject(string buketName)
            {
                try
                {
                    string bucket = _buketName + "-" + _appid; //存储桶名称 格式:BucketName-APPID
                    string key = "exampleobject"; //对象在存储桶中的位置,即称对象键.
                    DeleteObjectRequest request = new DeleteObjectRequest(bucket, key);
                    //设置签名有效时长
                    request.SetSign(TimeUtils.GetCurrentTime(TimeUnit.SECONDS), 600);
                    //执行请求
                    DeleteObjectResult result = await Task.FromResult(_cosXml.DeleteObject(request));
    
                    return new ResponseModel { Code = 200, Message = result.GetResultInfo() };
                }
                catch (CosClientException clientEx)
                {
                    return new ResponseModel { Code = 0, Message = "CosClientException: " + clientEx.Message };
                }
                catch (CosServerException serverEx)
                {
                    return new ResponseModel { Code = 0, Message = "CosServerException: " + serverEx.GetInfo() };
                }
            }
    

    以上代码将官方示例作了优化。

    • 依赖于抽象、实现接口;
    • 松耦合;
    • 异步网络流、异步文件流;
    • 统一返回信息;
    • 增加匿名委托作方法参数;
    • 增加灵活性。

    三,使用封装好的代码

    1,初始化

    官网示例文档:

    1565356983(1)

    使用修改后的代码,你可以这样初始化:

                var cosClient = new CosBuilder()
                    .SetAccount("1252707544", "	ap-guangzhou")
                    .SetCosXmlServer()
                    .SetSecret("AKIDEZohU6AmkeNTVPmedw65Ws462rVxLIpG", "Sn1iFi182jMARcheQ1gYIsGSROE5rSwG")
                    .Builder();
    

    简单测试代码

            static async Task Main(string[] args)
            {
                // 构建一个 CoxXmlServer 对象
                var cosClient = new CosBuilder()
                    .SetAccount("125x707xx4", "ap-guangzhou")
                    .SetCosXmlServer()
                    .SetSecret("AKIxxxxxxedw65Ws462rVxLIpG", "Sn1iFi1xxxxxwG")
                    .Builder();
                // 创建Cos连接客户端
                ICosClient client = new CosClient(cosClient, "125xx0xx44");
                // 创建一个存储桶
                var result = await client.CreateBucket("fsdgerer");
                Console.WriteLine("处理结果:" + result.Message);
                // 查询存储桶列表
                var c = await client.SelectBucket();
                Console.WriteLine(c.Message + c.Data);
    
                Console.ReadKey();
            }
    

    运行结果(部分重要信息使用xx屏蔽):

    处理结果:200 OK
    Connection: keep-alive
    Date: Fri, 09 Aug 2019 14:15:00 GMT
    Server: tencent-cos
    x-cos-request-id: xxxxxxxx=
    Content-Length: 0
    
    Success200 OK
    Connection: keep-alive
    Date: Fri, 09 Aug 2019 14:15:01 GMT
    Server: tencent-cos
    x-cos-request-id: xxxxxxx=
    Content-Type: application/xml
    Content-Length: 479
    
    {ListAllMyBuckets:
    {Owner:
    ID:qcs::cam::uin/1586xx146:uin/158xxx2146
    DisPlayName:158x2146
    }
    Buckets:
    {Bucket:
    Name:fsdgerer-125xxx7544
    Location:ap-guangzhou
    CreateDate:
    }
    {Bucket:
    Name:work-1252xxx7544
    Location:ap-guangzhou
    CreateDate:
    }
    }
    }
    
    

    其它不再赘述

  • 相关阅读:
    GIS单词汇总
    ArcGIS Server 开发初步 自定义工具
    ArcGIS Server 9.2 实现基于web浏览器的在线编辑
    控制图层是否显示的方法
    地图缓存与瓦片切割步骤
    汉字转拼音缩写(VB版)
    VB的Winsock控件GetData方法获取汉字乱码解决方法
    柱状专题图实现例子
    汉字转拼音缩写(C#版)
    ArcGIS Server .NET ADF中的AJAX之深入浅出/CallbackResult详解
  • 原文地址:https://www.cnblogs.com/whuanle/p/11329909.html
Copyright © 2011-2022 走看看