zoukankan      html  css  js  c++  java
  • Nuget服务的搭建-打包-上传-删除

    为了便于公共库的内部复用,我们可以架设自己的nuget服务。首先创建一个Asp.net的空项目NugetServer,其次使用nuget安装nuget.server包,如下图


    添加了nuget.server后,直接编译然后发布到IIS下,一个简单的nugetServer就搭建成功了。但是为了能更方便的操作,还需要加一些简单的功能,比如nuget包的上传和删除。

    在上传nuget包之前,还要知道nuget包的打包过程,需要用到打包工具NuGetPackageExplorer.application,点击下载即可。下面是打包的过程,按图顺序。






    打包后保存,生成了xxx.nuget文件直接复制到nuget服务的Packages文件夹下,参看下图


    之后在VS的nuget设置中,添加nuget服务的程序包源,参看下图


    之后在项目中搜索相应的包然后引用,参看下图


    选择相应的版本安装即可。

    在上面的过程中,nuget包打好后,是直接复制到服务器中的,但为了便于管理和操作,我们做了一个简单的上传和删除的页面来进行管理。

    上传的前端代码

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>上传</title>
        <meta charset="utf-8" />
        <link href="Stylesheets/style.css" rel="stylesheet" />
        <script src="Scripts/zepto.min.js"></script>
    </head>
    <body>
        <div id="ajaxWait" class="mask">
            <img src="Images/loading.gif" />
        </div>
        <div class="body">
            <div class="upload-container">
                <div>
                    <div class="upload-wrap">
                        <input type="file" id="filePackage" class="upload-pic" value="上传">
                        <span>
                            选择上传的包
                        </span>
                    </div>
                </div>
                <div><span id="filePackageInfo"></span></div>
            </div>
            <div>
                <input type="button" value="上传" id="btnUpload" class="upload-wrap " />
            </div>
        </div>
    </body>
    </html>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#btnUpload").click(function () {
                $("#ajaxWait").show();
                var formData = new FormData();
                formData.append("filePackage", document.getElementById("filePackage").files[0]);
                $.ajax({
                    url: "/api/Package/Upload",
                    type: "POST",
                    data: formData,
                    contentType: false,//必须false才会自动加上正确的Content-Type
                    processData: false,//必须false才会避开jQuery对 formdata 的默认处理.XMLHttpRequest会对 formdata 进行正确的处理.
                    success: function (data) {
                        $("#ajaxWait").hide();
                        if (data.Status == 0) {
                            alert("上传成功!");
                        }
                        else {
                            alert(data.Message);
                        }
                    },
                    error: function (data) {
                        $("#ajaxWait").hide();
                        alert("上传失败!" + data.Message);
                    }
                });
            });
    
            function fileInputChang(obj) {
                var id = obj.target.id;
                var files = document.getElementById(id).files;
                if (!files || files.length <= 0) {
                    img.src = "";
                    return;
                }
                var file;
                if (files && files.length > 0) {
                    // 获取目前上传的文件
                    file = files[0];
                    var size = '';
                    if (file.size > 1024 * 1024) {
                        size = (file.size / (1024 * 1024)).toFixed(2) + 'M';
                    }
                    else {
                        size = (file.size / 1024).toFixed(2) + 'K';
                    }
                    var name = file.name;
                    document.getElementById("filePackageInfo").innerHTML = name + " " + size;
                }
            }
    
            $("#filePackage").change(fileInputChang);
        });
    </script>
    

    删除的前端代码

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>查看/删除</title>
        <meta charset="utf-8" />
        <link href="Stylesheets/style.css" rel="stylesheet" />
        <script src="Scripts/zepto.min.js"></script>
    </head>
    <body>
        <div class="all">
            <div id="ajaxWait" class="mask">
                <img src="images/loading.gif" />
            </div>
            <div class="head">
                <h1>包列表</h1>
            </div>
            <div class="body">
                <div>
                    <table>
                        <tbody id="packageContainer"></tbody>
                    </table>
                </div>
                <div>
                    <input type="button" value="删除" id="btnDelete" class="btn" />
                </div>
            </div>
            <div class="footer"></div>
        </div>
    </body>
    </html>
    <script type="text/javascript">
        var g_packageList = {};
    
        function generateIndexListHtml() {
            var list = g_packageList;
            var html = "";
            var tr = "";
            var idFlag = "";
            for (var i = 0; i < list.length; i++) {
                if (i != 0 && i % 6 == 0) {
                    tr += "</tr>";
                    html += tr;
                    tr = "";
                }
                if (tr.length <= 0) {
                    tr += "<tr>";
                }
    
                var packageItem = list[i];            
                tr += '<td ><input  type="checkbox" id="checkbox_' + i + '"/></td> '
                    + '<td>' + packageItem.Name + '</td>'
                    + '<td>' + packageItem.Version + '</td>';
    
                if (i == list.length - 1) {
                    tr += "</tr>";
                    html += tr;
                    tr = "";
                }
            }
            return html;
        }
    
        function loadList() {
            $("#ajaxWait").show();
            $.ajax({
                type: 'get',
                url: "/api/Package/List",
                data: {},
                success: function (result) {
                    try {
                        if (result.Status != 0) {
                            $("#ajaxWait").hide();
                            alert(result.Message);
                            return;
                        }
                        g_packageList = result.Data;
                        var container = $('#packageContainer');
                        var html = generateIndexListHtml();
                        container.html(html);
                        $("#ajaxWait").hide();
    
                    } catch (e) {
                        $("#ajaxWait").hide();
                        alert(e.message);
                    }
                },
                error: function (result) {
                    $("#ajaxWait").hide();
                    alert("error");
                }
            });
        }
    
        $(document).ready(function () {
            loadList();
    
            $("#btnDelete").click(function () {
                if (!confirm("确定要删除吗?"))
                {
                    return;
                }
    
                var id = "";
                var list = [];
                for (var i = 0; i < g_packageList.length; i++) {
                    id = "checkbox_" + i;
                    if ($("#" + id).prop("checked")) {
                        list.push(g_packageList[i]);
                    }
                }
    
                $("#ajaxWait").show();
                $.ajax({
                    type: 'post',
                    url: "/api/Package/Delete",
                    data: JSON.stringify(list),
                    contentType: "application/json",
                    success: function (result) {
                        try {
                            $("#ajaxWait").hide();
                            if (result.Status != 0) {
                                alert(result.Message);
                                return;
                            }
                            loadList();
                        } catch (e) {
                            $("#ajaxWait").hide();
                            alert(e.message);
                        }
                    },
                    error: function (result) {
                        $("#ajaxWait").hide();
                        alert("error");
                    }
                });
            });
        });
    </script>
    


    上传和删除的后端代码(采用MVC的Controller来接收数据)

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Http;
    
    namespace NugetServer.Controllers
    {
        public class PackageController : ApiController
        {
            #region List
            [HttpGet]
            public BaseDataPackage<List<PackageItem>> List()
            {
                var result = new BaseDataPackage<List<PackageItem>>();
                try
                {
                    var packageItemList = new List<PackageItem>();
                    var physicsRoot = FetchPhysicsRootDir();
                    DirectoryInfo dirInfo = new DirectoryInfo(physicsRoot);
                    var dirs = dirInfo.GetDirectories();
                    PackageItem packageItem = null;
                    foreach (var dir in dirs)
                    {
                        var versionDirInfos = (new DirectoryInfo(dir.FullName)).GetDirectories();
                        foreach (var versionDirInfo in versionDirInfos)
                        {
                            packageItem = new PackageItem();
                            packageItem.Name = dir.Name;
                            packageItem.Version = versionDirInfo.Name;
                            packageItemList.Add(packageItem);
                        }
                    }
                    result.Data = packageItemList;
                    result.Message = "OK";
                    result.Status = StatusCode.OK;
                }
                catch (Exception ex)
                {
                    result.Data = null;
                    result.Message = ex.Message;
                    result.Status = StatusCode.Fail;
                }
                return result;
            }
            #endregion
    
            #region Upload
            [HttpPost]
            public BaseDataPackage<string> Upload()
            {
                var result = new BaseDataPackage<string>();
                if (!Request.Content.IsMimeMultipartContent())
                {
                    result.Status = StatusCode.Fail;
                    result.Message = "Data Invalid";
                    result.Data = null;
                    return result;
                }
    
                string physicsRoot = FetchPhysicsRootDir();
    
                var provider = new RenameMultipartFormDataStreamProvider(physicsRoot);
                IEnumerable<HttpContent> parts = null;
                Task.Factory
                    .StartNew(() =>
                    {
                        parts = Request.Content.ReadAsMultipartAsync(provider).Result.Contents;
                    },
                    CancellationToken.None,
                    TaskCreationOptions.LongRunning, // guarantees separate thread
                    TaskScheduler.Default)
                    .Wait();
    
                try
                {
                    if (provider != null && provider.FileNameList != null && provider.FileNameList.Count > 0)
                    {//刷新包缓存
                        RefreshPackageCache();
                    }
                    result.Status = StatusCode.OK;
                    result.Message = "OK";
                    result.Data = null;
                }
                catch (Exception ex)
                {
                    result.Status = StatusCode.Fail;
                    result.Message = ex.Message;
                    result.Data = null;
                }
    
                return result;
    
            }
    
            #region RenameMultipartFormDataStreamProvider
            /// <summary>
            /// 重命名上传的文件
            /// </summary>
            public class RenameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
            {
                #region 属性
                /// <summary>
                /// 上传的文件名列表
                /// </summary>
                public List<string> FileNameList { get; set; } = new List<string>();
                #endregion
    
                public RenameMultipartFormDataStreamProvider(string root)
                    : base(root)
                {
    
                }
    
                public override string GetLocalFileName(HttpContentHeaders headers)
                {
                    //截取文件扩展名
                    string fileName = headers.ContentDisposition.FileName.TrimStart('"').TrimEnd('"');
                    if (!FileNameList.Contains(fileName))
                    {
                        FileNameList.Add(fileName);
                    }
                    return fileName;
                }
            }
            #endregion
            #endregion
    
            #region FetchPhysicsRootDir
            private string FetchPhysicsRootDir()
            {
                var server = HttpContext.Current.Server;
                string webRoot = "~/Packages/";
                string physicsRoot = server.MapPath(webRoot);
    
                if (!Directory.Exists(physicsRoot))
                {
                    Directory.CreateDirectory(physicsRoot);
                }
                return physicsRoot;
            }
            #endregion
    
            #region RefreshPackageCache
            /// <summary>
            /// 刷新包缓存
            /// </summary>
            private void RefreshPackageCache()
            {
                var uri = HttpContext.Current.Request.Url;
                var port = uri.Port;
                var clearCacheApiUrl = VirtualPathUtility.ToAbsolute("~/nugetserver/api/clear-cache");//nuget服务的清除缓存API
                clearCacheApiUrl = "http://localhost:" + port.ToString() + clearCacheApiUrl;
                WebRequest request = WebRequest.Create(clearCacheApiUrl);
                request.Method = "GET";
                WebResponse response = request.GetResponse();
                Stream stream = response.GetResponseStream();
                Encoding encode = Encoding.UTF8;
                StreamReader reader = new StreamReader(stream, encode);
                string resultJson = reader.ReadToEnd();
            }
            #endregion
    
            #region Delete
            [HttpPost]
            public BaseDataPackage<string> Delete([FromBody] List<PackageItem> list)
            {
                var result = new BaseDataPackage<string>();
                if (list == null || list.Count <= 0)
                {
                    result.Status = StatusCode.OK;
                    result.Message = "删除列表为空";
                    return result;
                }
    
                try
                {
                    var physicsRoot = FetchPhysicsRootDir();
    
                    var temp = "";
                    foreach (var packageItem in list)
                    {
                        temp = physicsRoot + $"{packageItem.Name}\{packageItem.Version}";
                        DirectoryInfo di = new DirectoryInfo(temp);
                        di.Delete(true);
                    }
    
                    if (list != null && list.Count > 0)
                    {
                        RefreshPackageCache();
                    }
    
                    result.Status = StatusCode.OK;
                    result.Message = "OK";
                }
                catch (Exception ex)
                {
                    result.Status = StatusCode.Fail;
                    result.Message = ex.Message;
                }
                return result;
            }
            #endregion
        }
    
        #region PackageItem
        public class PackageItem
        {
            #region 属性
            /// <summary>
            /// 包名
            /// </summary>
            public string Name { get; set; }
    
            /// <summary>
            /// 版本
            /// </summary>
            public string Version { get; set; }
            #endregion
        }
        #endregion
    }
    用到的CSS

    .btn {
         100px;
        height: 34px;
        color: #fff;
        letter-spacing: 1px;
        background: #3385ff;
        border-bottom: 1px solid #2d78f4;
        outline: medium;
        -webkit-appearance: none;
        -webkit-border-radius: 0;
    }
    
    .upload-wrap {
        position: relative;
         158px;
        height: 43px;
        font-size: 16px;
        border: 1px solid #cacbcc;
        line-height: 43px;
        margin: 0 auto;
        color: #fff;
        text-align: center;
        background: #3385ff;
        border-bottom: 1px solid #2d78f4;
        float: left;
    }
    
    .upload-pic {
        position: absolute;
        font-size: 0;
         100%;
        height: 100%;
        outline: 0;
        opacity: 0;
        filter: alpha(opacity=0);
        margin-left: -18px;
        z-index: 1;
        cursor: pointer;
    }
    
    .upload-container {
        height:80px;
    }
    
    .mask{
         100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.8);
        position: fixed;
        top: 0;
        left: 0;
        z-index: 998;
        display: none;
        text-align:center;
        padding-top:10%;
    }
    
    相应的default.aspx页面也作了修改,代码如下

    <%@ Page Language="C#" %>
    
    <%@ Import Namespace="NuGet.Server" %>
    <%@ Import Namespace="NuGet.Server.Infrastructure" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>NuGet Private Repository</title>
        <style>
            body {
                font-family: Calibri;
            }
        </style>
    </head>
    <body>
        <div>
            <h2>NuGet.Server v<%= typeof(NuGet.Server.DataServices.ODataPackage).Assembly.GetName().Version %></h2>
            <fieldset style=" 800px">
                <legend><strong>包管理</strong></legend>
                <p><a href="delete.html" target="_blank">查看nuget包</a> <a href="upload.html" target="_blank">上传nuget包</a> </p>
                <p>
                    在包管理器中添加 <strong><%= Helpers.GetRepositoryUrl(Request.Url, Request.ApplicationPath) %></strong>作为包源(参照下图),以便使用自己构建的nuget服务.
                <img src="Images/nuget_source_set.png" />
                </p>
            </fieldset>
    
            <fieldset style=" 800px">
                <legend><strong>nuget打包</strong></legend>
                <div>
                    <a href="Kits/NuGetPackageExplorer.application">nuget打包工具下载</a>
                </div>
                <h3>打包工具使用说明</h3>
                <p>
                    <img src="Images/nuget_1.png" />
                    <img src="Images/nuget_2.png" />
                    <img src="Images/nuget_3.png" />
                </p>
            </fieldset>
        </div>
    </body>
    </html>
    
    编译发布后的结果,参看下面的图

    首面界面

    上传界面


    查看与删除包的界面

    源码下载

    转载请注明出处


  • 相关阅读:
    牛客IOI周赛17-提高组 卷积 生成函数 多项式求逆 数列通项公式
    6.3 省选模拟赛 Decompose 动态dp 树链剖分 set
    AtCoder Grand Contest 044 A Pay to Win 贪心
    5.29 省选模拟赛 树的染色 dp 最优性优化
    luogu P6097 子集卷积 FST FWT
    CF724C Ray Tracing 扩展欧几里得 平面展开
    5.30 省选模拟赛 方格操作 扫描线 特殊性质
    5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集
    Spring main方法中怎么调用Dao层和Service层的方法
    Bug -- WebService报错(两个类具有相同的 XML 类型名称 "{http://webService.com/}getPriceResponse"。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。)
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7604901.html
Copyright © 2011-2022 走看看