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>
    
    编译发布后的结果,参看下面的图

    首面界面

    上传界面


    查看与删除包的界面

    源码下载

    转载请注明出处


  • 相关阅读:
    matplotlib笔记(subplot)
    matplotlib笔记(plot)
    [时间序列处理]python中计算日期差
    Ubuntu 16.04 apt-get更换为国内阿里云源
    居然忘了range()的用法
    elasticsearch+kibana使用中踩的坑,持续更新中。
    Elasticsearch+Logstash+Kibana教程
    ubuntu下anaconda从清华镜像的下载安装及配置
    ubuntu 解决node 修改代码不能同步刷新的问题
    ubuntu18.04 解决sublimie不能使用中文
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7604901.html
Copyright © 2011-2022 走看看