当前位置: 首页 > news >正文

国产一级a做爰片免费网站wordpress 获取文章文字

国产一级a做爰片免费网站,wordpress 获取文章文字,短网址转换长网址,网站制作学习网站前言最近在开发新的项目#xff0c;使用的是ASP.NET Core6.0版本的框架。由于项目中存在文件下载功能#xff0c;没有使用类似MinIO或OSS之类的分布式文件系统#xff0c;而是下载本地文件#xff0c;也就是根据本地文件路径进行下载。这其中遇到了一个问题#xff0c;是关… 前言    最近在开发新的项目使用的是ASP.NET Core6.0版本的框架。由于项目中存在文件下载功能没有使用类似MinIO或OSS之类的分布式文件系统而是下载本地文件也就是根据本地文件路径进行下载。这其中遇到了一个问题是关于如何提供文件路径的通过本文记录一下相关总结希望能帮助更多的同学避免这个问题。使用方式由于我们的系统没有公司内部使用的也没有做负载均衡之类的所以文件是存储在当前服务器中的所以我们直接使用文件绝对路径的方式来进行下载的使用的是ASP.NET Core自带的File方法使用的是如下方法(实际上文件的路径是存储在数据库中的)[HttpGet] [Produces(application/msword, Type  typeof(FileResult))] public FileResult Virtual() {// AppContext.BaseDirectory用来获取当前执行程序的基目录// 结果为绝对路径,比如 D:\CodeProject\MyTest.WebApi\bin\Debug\net6.0\var filePath  Path.Combine(AppContext.BaseDirectory, files/疫情防控规范说明.docx);return File(filePath, application/msword, 疫情防控规范说明.docx); }这是比较常用的方式没太在意会有什么问题不过等自测的时候发现报了一个System.InvalidOperationException异常大致内容如下所示System.InvalidOperationException: No file provider has been configured to process the supplied file.at Microsoft.AspNetCore.Mvc.Infrastructure.VirtualFileResultExecutor.GetFileInformation(VirtualFileResult result, IWebHostEnvironment hostingEnvironment)at Microsoft.AspNetCore.Mvc.Infrastructure.VirtualFileResultExecutor.ExecuteAsync(ActionContext context, VirtualFileResult result)at Microsoft.AspNetCore.Mvc.VirtualFileResult.ExecuteResultAsync(ActionContext context)看异常内容问题是出在VirtualFileResultExecutor.GetFileInformation()方法它的意思大概是没有提供文件提供来处理文件对于文件提供程序如果了解过ASP.NET Core静态文件相关的话应该是了解这个的。如果想访问ASP.NET Core中的静态文件默认是不可以直接访问的这也是一种安全机制想使用的话必须开启静态文件访问机制且默认的静态文件要存储在wwwroot路径下。如果想在其它路径提供静态文件则必须要提供文件处理程序我们常用的方式则是var fileProvider  new PhysicalFileProvider(${env.ContentRootPath}/staticfiles); app.UseStaticFiles(new StaticFileOptions {RequestPath/staticfiles,FileProvider  fileProvider });同样的在这里我们也需要提供IFileProvider实例因为我们是使用的本地文件系统所以要提供PhysicalFileProvider实例通过下面方法解决了这个问题[HttpGet] [Produces(application/msword, Type  typeof(FileResult))] public FileResult Virtual() {var filePath  files/疫情防控规范说明.docx;return new VirtualFileResult(filePath, application/msword){// 提供指定目录的文件访问程序FileProvider  new PhysicalFileProvider(AppContext.BaseDirectory),FileDownloadName  疫情防控规范说明.docx}; }亦或者是通过原始的方式比如读取文件的Stream或者byte[]的方式[HttpGet] [Produces(application/msword, Type  typeof(FileResult))] public FileResult Virtual() {//读取byte[]方式var filePath  Path.Combine(AppContext.BaseDirectory, files\疫情防控规范说明.docx);var fileBytes  System.IO.File.ReadAllBytes(filePath);return File(fileBytes, application/msword, 疫情防控规范说明.docx);//读取Stream的方式//var filePath  Path.Combine(AppContext.BaseDirectory, files\疫情防控规范说明.docx);//var fileStream  System.IO.File.OpenRead(filePath);//return File(fileStream, application/msword, 疫情防控规范说明.docx); }通过这些方式虽然可以解决问题但是看起来不是很优雅而且如果提供不同路径的文件还得要有许多的PhysicalFileProvider实例或者自己封装方法去解决问题。当时就想微软不至于连读取自定义物理路径的方法都不提供吧于是就在ControllerBase基类中查找相关方法终于看到了一个叫PhysicalFile的方法看名字就知道是提供物理文件用的不知道行不行写代码试了试程序如下[HttpGet] [Produces(application/msword, Type  typeof(FileResult))] public FileResult Physical() {var filePath  Path.Combine(AppContext.BaseDirectory, files/疫情防控规范说明.docx);return PhysicalFile(filePath, application/msword, 疫情防控规范说明.docx); }结果还真的是可以这个方法呢提供的文件路径可以是文件的绝对路径而不需要提供别的文件提供程序。这就勾起了我的好奇心为啥两个操作还不一样呢为啥有这样的区别源码探究通过上面遇到的问题知道了如果想提供绝对路径的文件下载需要使用PhysicalFile方法去下载而默认的File方法则不能直接下载绝对路径的文件怀揣着好奇心大概看了一下这两个方法的相关源码实现。VirtualFileResult接下来咱们就来看一下方法的定义在ControllerBase类中现在来看一下File(string virtualPath, string contentType, string? fileDownloadName)方法的定义[点击查看源码[1]][NonAction] public virtual VirtualFileResult File(string virtualPath, string contentType, string? fileDownloadName) new VirtualFileResult(virtualPath, contentType) { FileDownloadName  fileDownloadName };通过virtualPath这个变量我们大概能猜出来默认提供的是相对目录即当前运行程序配置的相关目录。通过这段代码我们可以看到它的本质是VirtualFileResult这个类那我们继续找到VirtualFileResult类的实现[点击查看源码[2]]public class VirtualFileResult : FileResult {public VirtualFileResult(string fileName, string contentType): this(fileName, MediaTypeHeaderValue.Parse(contentType)){}public VirtualFileResult(string fileName, MediaTypeHeaderValue contentType): base(contentType.ToString()){FileName  fileName ?? throw new ArgumentNullException(nameof(fileName));}// 返回客户端的文件名称private string _fileName;public string FileName{get  _fileName;[MemberNotNull(nameof(_fileName))]set  _fileName  value ?? throw new ArgumentNullException(nameof(value));}//文件提供程序public IFileProvider? FileProvider { get; set; }/// summary/// 真正下载执行的方法/// /summarypublic override Task ExecuteResultAsync(ActionContext context){if (context  null){throw new ArgumentNullException(nameof(context));}//执行了IActionResultExecutorVirtualFileResult实例的ExecuteAsync方法var executor  context.HttpContext.RequestServices.GetRequiredServiceIActionResultExecutorVirtualFileResult();return executor.ExecuteAsync(context, this);} }在ASP.NET Core中Action的结果都是由IActionResultExecutor提供相关的实例具体的ExecuteResultAsync方法只是在执行IActionResultExecutor里的ExecuteAsync实现方法这个是在AddControllers方法的时候注册的可以通过源码找到IActionResultExecutorVirtualFileResult接口注册的实例[点击查看源码[3]]services.TryAddSingletonIActionResultExecutorVirtualFileResult, VirtualFileResultExecutor();由此我们可以知道IActionResultExecutorVirtualFileResult注册的是VirtualFileResultExecutor类所以我们可以直接查看VirtualFileResultExecutor类的ExecuteAsync方法的实现[点击查看源码[4]]public virtual Task ExecuteAsync(ActionContext context, VirtualFileResult result) {// 省略部分代码// 获取文件信息var fileInfo  GetFileInformation(result, _hostingEnvironment);// 文件不存在则抛出异常if (!fileInfo.Exists){throw new FileNotFoundException(Resources.FormatFileResult_InvalidPath(result.FileName), result.FileName);}Logger.ExecutingFileResult(result, result.FileName);var lastModified  result.LastModified ?? fileInfo.LastModified;var (range, rangeLength, serveBody)  SetHeadersAndLog(context,result,fileInfo.Length,result.EnableRangeProcessing,lastModified,result.EntityTag);if (serveBody){// 执行下载程序return WriteFileAsync(context, result, fileInfo, range, rangeLength);}return Task.CompletedTask; }通过这个方法可以知道判断文件信息存不存在是在GetFileInformation这个方法我们上面看到的那个异常也是在这个方法里报出来的所以我们看下这个方法的实现的看一下具体实现[点击查看源码[5]]/// summary /// 获取文件信息 /// /summary internal static IFileInfo GetFileInformation(VirtualFileResult result, IWebHostEnvironment hostingEnvironment) {// 获取文件提供程序var fileProvider  GetFileProvider(result, hostingEnvironment);//如果是NullFileProvider则直接抛出异常if (fileProvider is NullFileProvider){throw new InvalidOperationException(Resources.VirtualFileResultExecutor_NoFileProviderConfigured);}var normalizedPath  result.FileName;//特殊开头处理if (normalizedPath.StartsWith(~, StringComparison.Ordinal)){normalizedPath  normalizedPath.Substring(1);}//获取要下载的文件信息var fileInfo  fileProvider.GetFileInfo(normalizedPath);return fileInfo; }/// summary /// 获取文件提供程序 /// /summary internal static IFileProvider GetFileProvider(VirtualFileResult result, IWebHostEnvironment hostingEnvironment) {//判断是否设置了VirtualFileResult的FileProvider属性if (result.FileProvider ! null){return result.FileProvider;}//没设置则使用WebRootFileProvider即设置目录为wwwroot的文件提供程序result.FileProvider  hostingEnvironment.WebRootFileProvider;return result.FileProvider; }通过这段代码我们看到了问题的所在我们上面看到的异常位置的GetFileInformation方法也就是我们需要找到的位置这个地方获取到的IFileInfo是基于FileProvider的因此通过它获取的文件的物理路径是当前程序路径/WebRootFileProvider路径/传递的路径比如程序路径D:\CodeProject\MyTest.WebApi\bin\Debug\net6.0\WebRootFileProvider路径wwwroot\传递路径files\疫情防控规范说明.docx拼接而成因此在这里我们可以得到以下结论• 下载的文件信息是在IFileProvider实例中获取到的• GetFileProvider方法会判断是否手动设置了下载文件的IFileProvider,如果没有则使用IWebHostEnvironment的WebRootFileProvider实例即框架中wwwroot目录的文件提供程序• 我们提供绝对路径会抛出异常本质是我们没有提供需要下载文件的文件提供程序实例IFileProvider所以程序使用了wwwroot目录的文件提供程序所以可以得出结论我们如果想直接使用目录的话那指定的目录必须得是基于wwwroot文件夹的目录进行存储的也就是我们文件存储的文件夹得是在wwwroot里才行。比如我们将我们的上传的文件移动到wwwroot/files/文件夹内那么我们在编写下载程序相关代码的时候可以直接使用如下方式[HttpGet] [Produces(application/msword, Type  typeof(FileResult))] public FileResult Virtual() {var filePath  files/疫情防控规范说明.docx;return File(filePath, application/msword, 疫情防控规范说明.docx); }这样的话程序就可以运行成功了这也就解释了上面提供的File方法中提到的是virtualPath了。关于wwwroot机制在源码中可以看到[点击查看源码[6]]var webRoot  options.WebRoot; //判断配置里WebRoot是否配置 if (webRoot  null) {var wwwroot  Path.Combine(hostingEnvironment.ContentRootPath, wwwroot);//判断wwwroot目录是否存在if (Directory.Exists(wwwroot)){hostingEnvironment.WebRootPath  wwwroot;} } else {hostingEnvironment.WebRootPath  Path.Combine(hostingEnvironment.ContentRootPath, webRoot); } //判断IWebHostEnvironment中的WebRootPath是否存在 if (!string.IsNullOrEmpty(hostingEnvironment.WebRootPath)) {hostingEnvironment.WebRootPath  Path.GetFullPath(hostingEnvironment.WebRootPath);//目录不存在则创建wwwroot目录if (!Directory.Exists(hostingEnvironment.WebRootPath)){Directory.CreateDirectory(hostingEnvironment.WebRootPath);}//根据wwwroot路径创建WebRootFileProvider文件提供程序hostingEnvironment.WebRootFileProvider  new PhysicalFileProvider(hostingEnvironment.WebRootPath); } else {//如果没有提供wwwroot文件路径则赋值NullFileProviderhostingEnvironment.WebRootFileProvider  new NullFileProvider(); }通过这段代码相信大家对wwwroot默认的机制能有一定的了解了ASP.NET Core会根据程序是否包含wwwroot目录自行判断来填充IWebHostEnvironment实例中WebRootPath属性和WebRootFileProvider属性的值。所以可以先添加wwwroot文件夹然后基于这个目录添加自定义的文件夹这样可以直接使用File方法进行下载了。PhysicalFileResult上面我们了解到了VirtualFileResult的工作机制使用VirtualFileResult下载的时候默认需要提供虚拟的路径即基于当前应用的目录默认的是wwwroot目录。亦或者你可以自己提供IFileProvider机制来完成自定义目录的下载。但是当我们使用PhysicalFile()方法下载的时候却可以直接下载这是为什么呢同样的我们找到方法定义的地方[点击查看源码[7]][NonAction] public virtual PhysicalFileResult PhysicalFile(string physicalPath,string contentType,string? fileDownloadName) new PhysicalFileResult(physicalPath, contentType) { FileDownloadName  fileDownloadName };这里可以看到方法字段的名字是physicalPath也就是物理路径方法返回的是PhysicalFileResult类的实例。我们找到PhysicalFileResult类的ExecuteResultAsync方法的相关源码[点击查看源码[8]]public class PhysicalFileResult : FileResult {public PhysicalFileResult(string fileName, string contentType): this(fileName, MediaTypeHeaderValue.Parse(contentType)){if (fileName  null){throw new ArgumentNullException(nameof(fileName));}}public PhysicalFileResult(string fileName, MediaTypeHeaderValue contentType): base(contentType.ToString()){FileName  fileName ?? throw new ArgumentNullException(nameof(fileName));}// 返回客户端的文件名称private string _fileName;public string FileName{get  _fileName;[MemberNotNull(nameof(_fileName))]set  _fileName  value ?? throw new ArgumentNullException(nameof(value));}/// summary/// 真正下载执行的方法/// /summarypublic override Task ExecuteResultAsync(ActionContext context){if (context  null){throw new ArgumentNullException(nameof(context));}var executor  context.HttpContext.RequestServices.GetRequiredServiceIActionResultExecutorPhysicalFileResult();return executor.ExecuteAsync(context, this);} }通过这个类可以看出相较于VirtualFileResult类少了FileProvider属性这也说明了确实是不需要传递文件访问程序。ExecuteResultAsync方法是完全透明的核心逻辑在IActionResultExecutorPhysicalFileResult实例中[点击查看源码[9]]services.TryAddSingletonIActionResultExecutorPhysicalFileResult, PhysicalFileResultExecutor();照旧我们直接找到我们可以直接查看PhysicalFileResultExecutor类的ExecuteAsync方法的实现[点击查看源码[10]]public virtual Task ExecuteAsync(ActionContext context, PhysicalFileResult result) {//省略代码//获取文件信息var fileInfo  GetFileInfo(result.FileName);//文件不存在则抛出异常if (!fileInfo.Exists){throw new FileNotFoundException(Resources.FormatFileResult_InvalidPath(result.FileName), result.FileName);}Logger.ExecutingFileResult(result, result.FileName);var lastModified  result.LastModified ?? fileInfo.LastModified;var (range, rangeLength, serveBody)  SetHeadersAndLog(context,result,fileInfo.Length,result.EnableRangeProcessing,lastModified,result.EntityTag);if (serveBody){// 真正执行下载return WriteFileAsync(context, result, range, rangeLength);}return Task.CompletedTask; }同样的是在GetFileInfo方法里看一下定义protected virtual FileMetadata GetFileInfo(string path) {//直接根据传进来的路径获取的文件信息var fileInfo  new FileInfo(path);return new FileMetadata{Exists  fileInfo.Exists,Length  fileInfo.Length,LastModified  fileInfo.LastWriteTimeUtc,}; }区别主要就是在这个方法这里是直接根据文件的绝对路径获取的文件信息而不需要借助FileProvider,因此如果你传递的是D:\CodeProject\MyTest.WebApi\bin\Debug\net6.0\wwwroot\files\疫情防控规范说明.docx那么获取到的文件信息也是来自于这个路径也就是文件的绝对路径。SendFileAsync方法咱们看到的逻辑都是为了获取到文件的真实路径而真正执行下载的是WriteFileAsync方法这个方法的核心逻辑其实就是调用了HttpResponse的扩展方法SendFileAsync方法所以如果你不想用FileResult类相关方法提供下载的时候可以使用这个方法唯一比较麻烦的就是下载的Header信息你得自己填充上去简单的示例一下[HttpGet] public Task SendFile() {var filePath  Path.Combine(AppContext.BaseDirectory, files/疫情防控规范说明.docx);//获取fileInfovar fileInfo  new FileInfo(filePath);ContentDispositionHeaderValue contentDispositionHeaderValue  new ContentDispositionHeaderValue(attachment);contentDispositionHeaderValue.FileName fileInfo.Name;// 设计ContentDisposition头信息Response.Headers.ContentDisposition  contentDispositionHeaderValue.ToString();//设置ContentLength头信息Response.ContentLength  new long?(fileInfo.Length);//调用SendFileAsync方法return Response.SendFileAsync(filePath, 0L, null, default); }Results.File从ASP.NET Core6.0开始就提供了MinimalApi写法MinimalApi同样可以执行文件下载使用的是Results.File方法。这个方法就比较有意思了比较智能。无论你是传递虚拟路径或者是物理路径都是可以的不用你单独的去操作别的什么了比如以下代码//相对路径下载 app.MapGet(/virtual, ()  {var virtualPath  files/疫情防控规范说明.docx;return Results.File(virtualPath, application/msword, 疫情防控规范说明.docx); });//物理路径下载 app.MapGet(/physical, ()  {var physicalPath  Path.Combine(AppContext.BaseDirectory, files/疫情防控规范说明.docx);return Results.File(physicalPath, application/msword, 疫情防控规范说明.docx); });上面的两种方式都是可以正常执行的而且不会报错相对来说变得更高级一点了那具体是如何操作的呢我们来看一下Results.File方法的实现[点击查看源码[11]]public static IResult File(string path,string? contentType  null,string? fileDownloadName  null,DateTimeOffset? lastModified  null,EntityTagHeaderValue? entityTag  null,bool enableRangeProcessing  false) {//判断路径是否包含根目录if (Path.IsPathRooted(path)){// 包含根目录则是绝对路径直接使用PhysicalFileResultreturn new PhysicalFileResult(path, contentType){FileDownloadName  fileDownloadName,LastModified  lastModified,EntityTag  entityTag,EnableRangeProcessing  enableRangeProcessing,};}else{// 表示虚拟路径也就是当前程序指定的路径return new VirtualFileResult(path, contentType){FileDownloadName  fileDownloadName,LastModified  lastModified,EntityTag  entityTag,EnableRangeProcessing  enableRangeProcessing,};} }通过这个方法我们可以看到Results.File已经帮我们在内部进行了判断是符合物理路径还是虚拟路径。如果是物理路径则直接返回PhysicalFileResult实例也就是ControllerBase类中的PhysicalFile方法的类型。如果是相对路径则返回VirtualFileResult实例也就是上面ControllerBase类中的File方法。总结    本篇文章起源是由笔者在实际开发项目中根据文件路径下载文件出现异常并找到了相应的解决方法。出于好奇的本心研究了一下相关的实现。在ASP.NET Core中文件路径分为两类。一种是绝对的物理路径一种是在程序中设置的相对路径不同路径的文件下载有不同的文件处理方法大致总结一下• VirtualFileResult类型的文件下载默认路径是由WebRootFileProvider提供的路径即wwwroot文件夹的路径所以这个时候提供的文件路径是相对路径真实文件也是存储在wwwroot路径下的你可以可以定义自己的IFileProvider实例来传递自己的路径。• PhysicalFileResult类型的文件下载路径则是直接传递进来的物理路径是绝对路径也就是当前程序所在服务器或者操作系统的真实路径。这个路径程序不经过加工是确实存在的路径。• MinimalApi的Results.File方法不需要我们认为的判断是相对路径还是绝对路径直接使用即可。因为方法内已经帮我们做了判断了。• 文件下载则是调用了HttpResponse的扩展方法SendFileAsync方法。这一部分逻辑整体来说还是比较清晰的相信大家理解起来也会比较容易。我们学习的过程最核心的就是积累经验但是积累的经验一定是一系列的抽象概念我们可以称它为思维标签这是我们可以复用的底层逻辑。借用刘润的话来说只有不同之中的相同之处、变化背后不变的东西才是底层逻辑。只有底层逻辑才是有生命力的。只有底层逻辑在我们面临环境变化时才能被应用到新的变化中从而产生适应新环境的方法论。只有掌握了底层逻辑只有探寻到万变中的不变才能动态地、持续地看清事物的本质。引用链接[1] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/ControllerBase.cs#L1473[2] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/VirtualFileResult.cs[3] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/DependencyInjection/MvcCoreServiceCollectionExtensions.cs#L250[4] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs#L41[5] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs#L126[6] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Hosting/Hosting/src/Internal/HostingEnvironmentExtensions.cs#L33[7] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/ControllerBase.cs#L1628[8] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/PhysicalFileResult.cs#L59[9] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/DependencyInjection/MvcCoreServiceCollectionExtensions.cs#L249[10] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs#L29[11] 点击查看源码: https://github.com/dotnet/aspnetcore/blob/v6.0.6/src/Http/Http.Results/src/Results.cs#L318
http://www.zqtcl.cn/news/735991/

相关文章:

  • 手机开发网站教程做古建的那些网站比较适合
  • 网站建设公司的前景长沙商城网站开发
  • 大型网站tag标签 索引自己做网站需要哪些软件
  • 石排做网站万网网站备案流程
  • 南京建设银行网站首页简单的ui界面制作
  • 门户网站 建设 如何写如何布置网站
  • 网站前台功能模块介绍建设银行信用卡网站是哪个好
  • 用python做网站我那些网站开发开发语言
  • 建设网站怎样做安卓app软件公司
  • 重庆seo整站优化效果上海城建建设官方网站
  • 做淘宝要网站兰州画册设计
  • 外贸网站排行榜前十名电影网站标题怎么做流量多
  • 网站建设吉金手指专业13网站备案完成后不解析
  • 社保网站减员申报怎么做长春建筑网站
  • 网站开发用原生wordpress读者墙
  • 食品网站网页设计成都建网页
  • 网站建设 珠海专业团队表情包张伟
  • 建设铝合金窗网站.net制作网站开发教程
  • 网站后台服务器内部错误wordpress 多级菜单
  • 怎样更新网站内容怎么查看网站是哪家公司做的
  • 建设网站网站建站建立一个网站平台需要多少钱
  • 学校网站模板 html网站建设技术路线
  • 图片网站如何做百度排名深入挖掘wordpress
  • 网站建设的前景网站建设分为哪三部分
  • 房地产公司网站下载校园二手信息网站建设
  • 有关网站空间不正确的说法是设计和建设企业网站心得和体会
  • 个人网站前置审批项怎么做投票 网站
  • 网站建设零金手指花总js源码下载从哪个网站能下载
  • 网站开发属于无形资产两人合伙做网站但不准备开公司
  • 五大类型网站网站建设投标文件