.net core 除了继续保留.net framework的HtmlHelper的写法以外,还提供了TagHelper和ViewComponent方式生成控件。

我们本节说的是使用TagHelper来生成控件。不过严格的说起来,TagHelper是对客户端html元素的辅助类,例如渲染、增加服务端特性等。我们可以使用 taghelper 定义自己的标签或更改已知标签。使用TagHelper,VS.net编译环境也可以自动感知,并提供智能提示。因为TagHelper生成的控件,看起来像一个原生的HTML标签一样,也更利于美工进行页面美化。

例如一个lable控件 <label asp-for="Email"></label>,生成的最终html就是这样:<label for="Email">xxx@xx.com</label>

如果要使用TagHelper,除了在页面中using 命名空间之外,还需要使用@addTagHelper来使TagHelper可用。由于我们会编写不止一个TagHelper,且在多个cshtml页面使用,因此我们将如下代码

@using MicroStrutLibrary.Presentation.Web.Controls

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@addTagHelper *, MicroStrutLibrary.Presentation.Web.Controls

写在视图文件 Views/_ViewImports.cshtml中。写在Views/_ViewImports.cshtml的意思是,默认所有的在 Views 和Views下级目录中的视图文件都可以使用TagHelper,通配符 ("*") 来指定在特定程序集(Microsoft.AspNetCore.Mvc.TagHelpers和MicroStrutLibrary.Presentation.Web.Controls)中的所有的 TagHelpers 在 Views目录和子目录中的视图文件中都是可用的。第一个程序集是mvc自带的,第二个是我们自己的控件程序集。具体的说明大家还是看.net core文档吧。

下面,我们仍旧以上一节介绍的多选控件MultiSelect为例,说明下我们的TagHelper封装过程。

MultiSelect在cshtml中的写法如下,asp-dataSource传入的是数据源,select的所有下拉内容都是通过datasource生成的,而asp-value传入的是选中的项:

 @model Dictionary<string, string>
@{
List<string> values = ViewData.Get<List<string>>("Values");
} <multiSelect id="txtInput0" asp-dataSource="@Model" asp-value="@values"></multiSelect>

Model和values从controller中传过来的,具体如下:

         public IActionResult MultiSelect()
{
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("", "Aaaaa");
data.Add("", "Aaron");
data.Add("", "Abbott");
data.Add("", "Abel");
data.Add("", "Abner");
data.Add("", "Abraham");
data.Add("", "Adair");
data.Add("", "Adam");
data.Add("", "Addison"); List<string> value = new List<string>();
value.Add("");
value.Add("");
ViewData["Values"] = value; return View(data);
}

这样,最终生成的html代码和页面如下:

 <div>
<select id="txtInput0" name="txtInput0" multiple="multiple">
<option value="1" >Aaaaa</option>
<option value="2" selected>Aaron</option>
<option value="3" >Abbott</option>
<option value="4" >Abel</option>
<option value="5" >Abner</option>
<option value="6" >Abraham</option>
<option value="7" selected>Adair</option>
<option value="8" >Adam</option>
<option value="9" >Addison</option>
</select>
<script>
require(['jquery', 'bootstrap', 'multiselect'], function ($) {
$(function(){
$("#txtInput0").multiselect({
nonSelectedText: '请选择',
enableFiltering: true,//是否显示过滤
filterPlaceholder: '查找',
includeSelectAllOption: true,//是否显示全选
selectAllText: '全选',
numberDisplayed: 5//显示条数
});
});
});
</script>
</div>

MultiSelect在页面展示如下图

按照设计,MultiSelect应该能够传入:1、数据源,也就是下拉列表的所有数据;2、已选项,已选择的数据;3、下拉列表的展示条数,以免条数过多,影响页面;4、是否只读等属性,更好的控制控件的展示内容。当然了,还应该包括一个For属性,这个For属性的意思是通过页面的Model绑定,自动生成控件Id和已选择数据项等内容。

由于所有的TagHelper都继承于一个基类TagHelper,我们首先看下TagHelper抽象类:

     //
// 摘要:
// Class used to filter matching HTML elements.
public abstract class TagHelper : ITagHelper
{
protected TagHelper(); //
// 备注:
// Default order is 0.
public virtual int Order { get; } //
public virtual void Init(TagHelperContext context);
//
// 摘要:
// Synchronously executes the Microsoft.AspNetCore.Razor.TagHelpers.TagHelper with
// the given context and output.
//
// 参数:
// context:
// Contains information associated with the current HTML tag.
//
// output:
// A stateful HTML element used to generate an HTML tag.
public virtual void Process(TagHelperContext context, TagHelperOutput output);
//
// 摘要:
// Asynchronously executes the Microsoft.AspNetCore.Razor.TagHelpers.TagHelper with
// the given context and output.
//
// 参数:
// context:
// Contains information associated with the current HTML tag.
//
// output:
// A stateful HTML element used to generate an HTML tag.
//
// 返回结果:
// A System.Threading.Tasks.Task that on completion updates the output.
//
// 备注:
// By default this calls into Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.Process(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext,Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput).
public virtual Task ProcessAsync(TagHelperContext context, TagHelperOutput output);
}

这里最重要的就是Process方法和ProcessAsync方法。这两个方法,一个是同步,一个是异步,作用都是输出页面html代码。

我们再来看封装后的MultiSelectTagHelper的代码:

     [HtmlTargetElement("multiSelect", Attributes = ForAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = ValueAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = ShowItemCountAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = DataSourceAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = ReadonlyAttributeName)]
public class MultiSelectTagHelper : TagHelper
{
private readonly IHtmlGenerator generator; public MultiSelectTagHelper(IHtmlGenerator generator)
{
this.generator = generator;
} private const string ForAttributeName = "asp-for";
private const string ValueAttributeName = "asp-value";
private const string ShowItemCountAttributeName = "asp-showItemCount";
private const string DataSourceAttributeName = "asp-dataSource";
private const string ReadonlyAttributeName = "asp-readonly"; [HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; } [HtmlAttributeName(ForAttributeName)]
public ModelExpression For { get; set; } [HtmlAttributeName(ValueAttributeName)]
public List<string> Value { get; set; } [HtmlAttributeName(ShowItemCountAttributeName)]
public int ShowItemCount { get; set; } = ; [HtmlAttributeName(DataSourceAttributeName)]
public Dictionary<string, string> DataSource { get; set; } [HtmlAttributeName(ReadonlyAttributeName)]
public bool Readonly { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output)
{
MicroStrutLibraryExceptionHelper.IsNull(context, this.GetType().FullName, LogLevel.Error, "context参数值为空");
MicroStrutLibraryExceptionHelper.IsNull(output, this.GetType().FullName, LogLevel.Error, "output"); output.TagName = "div";
//output.Attributes.Add("class", "multiselect-drop"); MultiSelectList selectList = new MultiSelectList(this.DataSource, "Key", "Value", this.Value); HtmlContentBuilder builder = new HtmlContentBuilder(); string id;
if (For == null)
{
id = output.Attributes["id"].Value.ToString();
output.Attributes.Remove(output.Attributes["id"]); string options = string.Empty;
foreach (SelectListItem item in selectList)
{
options += $"<option value=\"{item.Value}\" {(item.Selected ? "selected" : "")}>{item.Text}</option>";
} builder.AppendHtml($"<select id=\"{id}\" name=\"{id}\" multiple=\"multiple\">{options}</select>");
}
else
{
id = For.Name; TagBuilder dropDown = generator.GenerateSelect(ViewContext, For.ModelExplorer, For.Name, string.Empty, selectList, true, null);
builder.AppendHtml(dropDown);
} string readOnly = "";
if (this.Readonly)
{
readOnly = $"$('#{id} +div > button').attr('disabled', true);";
}
string script = string.Format(@"
<script>
require(['jquery', 'bootstrap', 'multiselect'], function ($) {{
$(function(){{
$(""#{0}"").multiselect({{
nonSelectedText: '请选择',
enableFiltering: true,//是否显示过滤
filterPlaceholder: '查找',
includeSelectAllOption: true,//是否显示全选
selectAllText: '全选',
numberDisplayed: {1}//显示条数
}});
{2}
}});
}});
</script>
", id, this.ShowItemCount, readOnly); builder.AppendHtml(script); output.Content.AppendHtml(builder); base.Process(context, output);
}
}

为了在编写程序时不会出错,我们定义了五个常量ForAttributeName 、ValueAttributeName、ShowItemCountAttributeName、DataSourceAttributeName、ReadonlyAttributeName,分别代表MultiSelect标签的asp-for等Attribute。也就是MultiSelect传入的数据源、已选项、下拉列表的展示条数、是否只读等属性、For属性。

类定义上面[HtmlTargetElement("multiSelect", Attributes = ValueAttributeName)]的作用是在multiSelect标签上生成ValueAttributeName对应值asp-value的Attribute。

属性上面

[HtmlAttributeName(ValueAttributeName)]

public List<string> Value { get; set; }

的作用是告诉multiSelect标签,asp-value传入的应该是个List<string>类型。这里需要注意的是,在各种文档、教程中,大多数情况下,Attribute传入的类型都是一些简单类型,例如字符串、数字等。其实Attribute是可以传入复杂的类型的,例如我们这里传入的List<string>。页面中也就要如下的使用方式:

 @model Dictionary<string, string>
@{
List<string> values = ViewData.Get<List<string>>("Values");
} <multiSelect id="txtInput0" asp-dataSource="@Model" asp-value="@values"></multiSelect>

还有一个属性ViewContext,这个属性不是显式传入的,而是TagHelper创建时,系统自动赋值的,含义是当前的视图执行上下文Microsoft.AspNetCore.Mvc.Rendering.ViewContext。

[HtmlAttributeNotBound]

[ViewContext]

public ViewContext ViewContext { get; set; }

这里还有一个需要重要说明的是For方式public ModelExpression For { get; set; }。普通方式下,multiSelect的Id、Value都是从页面传入的,但是For方式是与Model绑定的,如同HtmlHelper的TextBox、TextBoxFor的区别一样。例如,一个人可能有多个职责,人的职责属性是DutyList,所有职责的数据DutyDictionary,在cshtml页面中就按照如下方式写multiselect:

@model UserInfo

<multiSelect asp-dataSource="@DutyDictionary" asp-for="DutyList"></multiSelect>

MultiSelect构造函数中,传入了一个IHtmlGenerator参数,这个是通过DI容器自动解析出来的,缺省情况下的实现类是DefaultHtmlGenerator。这个类的主要作用是生成各种html标签。我们在For方式用到了自动生成select标签的方法。TagBuilder dropDown = generator.GenerateSelect(ViewContext, For.ModelExplorer, string.Empty, For.Name, selectList, true, null);

最后就是重写Process方法。其实这个方法还是比较简单的,当For方式时,通过For自动生成select;否则就自己写select。我们其中还写了一段脚本,脚本中直接引用了jquery的MultiSelect脚本,

require(['jquery', 'bootstrap', 'multiselect'], function ($) {{…

这里我们使用systemjs这个通用的javascript模块加载器,其中的jquery、bootstrap、multiselect都是在system.config中定义的。System.config.js的代码大体如下,至于为什么这么写,大家还是搜网上帮助吧:

     System.config({
bundles: {
},
paths: {
"external:": externalUrl+"/"
},
map: {
"jquery": "external:lib/jquery/jquery.min.js",
"bootstrap": "external:lib/bootstrap/js/bootstrap.min.js", //--
"jquery-ui": "external:lib/jquery/jquery-ui/jquery-ui.bundle.min.js", //--Plugins
"multiselect": "external:lib/plugins/multiselect/js/bootstrap-multiselect.min.js"

},
meta: {
'*.css': {
loader: 'external:lib/system/css-loader/css.js'
},
'jquery': {
format: 'global',
exports: 'jQuery'
},
'bootstrap': {
format: 'global',
deps: ['jquery']
},
'jquery-ui': {
format: 'global',
deps: ['jquery','./jquery-ui.min.css']
},
'multiselect': {
format: 'global',
deps: ['../css/bootstrap-multiselect.min.css']
},

},
packages: {
'/js': {
format: 'cjs',
defaultExtension: 'js'
}, //externals
'external:js': {
format: 'cjs',
defaultExtension: 'js'
}
}
}); //amd require
window.require = System.amdRequire;

至此,一个基本的Taghelpr就完成了。

在ASP.NET Core MVC中应该使用 TagHelpers 来替换 HtmlHelpers,因为它们更加的简洁和容易使用。另一个巨大的好处就是依赖注入,在HtmlHelpers中是使用不了的,因为HtmlHelpers 扩展的都是静态内容。 但TagHelpers是一个公共类,我们可以很容易的在它的构造函数中注入服务。

进阶:资源性视图的应用

按照上节的惯例,我们依旧还一个进阶,说明下在TagHelper中如何使用cshtml,以及cshtml作为嵌入的资源该如何写。

我们从上面MultiSelectTagHelper类中将Process方法的页面代码拼接程序提取出来,写成cshtml如下

 @{
string id = ViewData["Id"].ToString();
int showItemCount = (int)ViewData["ShowItemCount"];
bool isReadonly = (bool)ViewData["Readonly"];
} <script>
require(['jquery', 'bootstrap', 'multiselect'], function ($) {
$(function(){
$("#@id").multiselect({
nonSelectedText: '请选择',
enableFiltering: true,//是否显示过滤
filterPlaceholder: '查找',
includeSelectAllOption: true,//是否显示全选
numberDisplayed: @(showItemCount),//显示条数
selectAllText: '全选'
});
@if (isReadonly)
{
@:$("#@id +div > button").attr("disabled", true);
}
});
});
</script>

这样MultiSelectTagHelper类中就简化成如下:

     [HtmlTargetElement("multiSelect", Attributes = ForAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = ValueAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = ShowItemCountAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = DataSourceAttributeName)]
[HtmlTargetElement("multiSelect", Attributes = ReadonlyAttributeName)]
public class MultiSelectTagHelper : TagHelper
{
private readonly IHtmlGenerator generator;
private readonly IUrlHelperFactory factory;
private readonly IHtmlHelper htmlHelper; public MultiSelectTagHelper(IHtmlHelper htmlHelper, IHtmlGenerator generator)
{
this.generator = generator;
this.factory = factory;
this.htmlHelper = htmlHelper;
} private const string ForAttributeName = "asp-for";
private const string ValueAttributeName = "asp-value";
private const string ShowItemCountAttributeName = "asp-showItemCount";
private const string DataSourceAttributeName = "asp-dataSource";
private const string ReadonlyAttributeName = "asp-readonly"; [HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; } [HtmlAttributeName(ForAttributeName)]
public ModelExpression For { get; set; } [HtmlAttributeName(ValueAttributeName)]
public List<string> Value { get; set; } [HtmlAttributeName(ShowItemCountAttributeName)]
public int ShowItemCount { get; set; } = ; [HtmlAttributeName(DataSourceAttributeName)]
public Dictionary<string, string> DataSource { get; set; } [HtmlAttributeName(ReadonlyAttributeName)]
public bool Readonly { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output)
{
MicroStrutLibraryExceptionHelper.IsNull(context, this.GetType().FullName, LogLevel.Error, "context参数值为空");
MicroStrutLibraryExceptionHelper.IsNull(output, this.GetType().FullName, LogLevel.Error, "output"); output.TagName = "div";
//output.Attributes.Add("class", "multiselect-drop"); MultiSelectList selectList = new MultiSelectList(this.DataSource, "Key", "Value", this.Value); HtmlContentBuilder builder = new HtmlContentBuilder(); string id;
if (For == null)
{
id = output.Attributes["id"].Value.ToString();
output.Attributes.Remove(output.Attributes["id"]); string options = string.Empty;
foreach (SelectListItem item in selectList)
{
options += $"<option value=\"{item.Value}\" {(item.Selected ? "selected" : "")}>{item.Text}</option>";
} builder.AppendHtml($"<select id=\"{id}\" name=\"{id}\" multiple=\"multiple\">{options}</select>");
}
else
{
id = For.Name; TagBuilder dropDown = generator.GenerateSelect(ViewContext, For.ModelExplorer, null, For.Name, selectList, true, null);
builder.AppendHtml(dropDown);
} output.Content.AppendHtml(builder); //Contextualize the html helper
(htmlHelper as IViewContextAware).Contextualize(ViewContext); ViewDataDictionary data = new ViewDataDictionary(this.ViewContext.ViewData);
data["Id"] = id;
data["ShowItemCount"] = this.ShowItemCount;
data["Readonly"] = this.Readonly; var content = htmlHelper.Partial("TagHelpers/MultiSelect/MultiSelect", data);
output.Content.AppendHtml(content); base.Process(context, output);
}
}
}

大家可能注意到构造函数中我们增加了个参数IHtmlHelper htmlHelper。这个参数是之前MVC的HtmlHelper,我们通过DI方式直接获取到htmlhelper。然而,此时DI获取的htmlhelper还无法使用,必须通过(htmlHelper as IViewContextAware).Contextualize(ViewContext);将上下文信息传入HtmlHelper。var content = htmlHelper.Partial("TagHelpers/MultiSelect/MultiSelect", data); output.Content.AppendHtml(content);这两句话执行cshtml页面,将最终页面的内容呈现在TagHelper中。

这里还有一个问题,就是我们将所有的控件都存放到一个应用程序集中,控件的cshtml页面也会以资源方式打包进应用程序集中。我们控件的项目结构如下:

MultiSelect的内容如下,有2个文件,一个cshtml,一个是taghelper程序。其他目录的结构也是类似的。

新的.net core的嵌入资源方式需要在project.json中按照如下方式编写:

"buildOptions": {

"embed": [ "Components/**/*.cshtml", "TagHelpers/**/*.cshtml" ]

}

这里的意思是我们将所有components和taghelpers目录下的第二级子目录下的所有cshtml文件以嵌入方式打包进应用程序集中。在.net core中使用应用程序集中嵌入的文件,还算是比较方便。因为.net core已经把许多可扩展的内容开放出来了。

我们这里写了一个扩展方法,在RazorViewEngineOptions(RazorViewEngine程序方式的配置)中增加一个Razor视图文件的定位器EmbeddedFileProvider。EmbeddedFileProvider就可以获取应用程序集中嵌入的cshtml文件,构造函数第一个参数是包含嵌入cshtml文件的应用程序集,第二个参数是命名空间。

     public static class EmbeddedViewServiceCollectionExtensions
{
public static IServiceCollection AddEmbeddComponentView(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
} EmbeddedFileProvider fileProvider = new EmbeddedFileProvider(typeof(EmbeddedViewServiceCollectionExtensions).GetTypeInfo().Assembly, "MicroStrutLibrary.Presentation.Web.Controls"); services.Configure<RazorViewEngineOptions>(options => {
options.FileProviders.Add(fileProvider);
}); return services;
}
}

接下来就是在Startup.cs中使用这个扩展方法:

 public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{

}); services.AddEmbeddComponentView();
}

现在才发现,其实生成select标签部分也是应该放到csthml中的,而不是在taghelper中生成,就不改了啊:)。

这里主要有几个小技巧再提示下:

1、cshtml页面中,Taghelper的Attribute可以传入各种复杂对象,而不是string\int\bool等简单类型

2、TagHelper如果使用cshtml,则应该使用IHtmlHelper

3、嵌入资源方式的cshtml,需要使用embeddedfileprovider。

面向云的.net core开发框架

9.2.3 .net core 通过TagHelper封装控件的更多相关文章

  1. [转]9.2.3 .net core 通过TagHelper封装控件

    本文转自:https://www.cnblogs.com/BenDan2002/p/6170624.html .net core 除了继续保留.net framework的HtmlHelper的写法以 ...

  2. 9.2.4 .net core 通过ViewComponent封装控件

    我们在.net core中还使用了ViewComponent方式生成控件.ViewComponent也是asp.net core的新特性,是对页面部分的渲染,以前PartialView的功能,可以使用 ...

  3. [转].net core 通过ViewComponent封装控件 左侧菜单

    本文转自:http://www.cnblogs.com/BenDan2002/p/6224816.html 我们在.net core中还使用了ViewComponent方式生成控件.ViewCompo ...

  4. wheelView实现滚动选择 三方开源的封装控件 spannableString autofitTextView、PinnedSectionListView SwipeListView等等

    wheelView多用于popupwindow用来滚动选择条目 github上的开源三方控件     spannableString   autofitTextView.PinnedSectionLi ...

  5. 一步一步学Silverlight 2系列(8):使用样式封装控件观感

    述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...

  6. WPF封装控件时 检测是否在设计模式中

    原文:WPF封装控件时 检测是否在设计模式中 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Vblegend_2013/article/detail ...

  7. TWinControl的刷新过程(5个非虚函数,4个覆盖函数,1个消息函数,默认没有双缓冲,注意区分是TCustomControl还是Windows原生封装控件,执行流程不一样)

    前提条件:要明白在TWinControl有以下四个函数的存在,注意都是虚函数: procedure Invalidate; override;procedure Update; override;pr ...

  8. mvc 封装控件使用mvcpager

    具体使用如下: 前台部分: @RenderPage("~/Views/Controls/_Pagebar.cshtml", new PageBar { pageIndex = Mo ...

  9. 9.2.2 .net framework下的MVC 控件的封装(下)

    控件封装的部分说明 可能有人觉得应该前后端分离,我也承认这是应该的方向,我们也在考虑使用ng2等简化前端.但是,我们封装控件还是因为如下原因综合考虑的: 我们这是个框架,上面支撑了许多个应用,包含几百 ...

随机推荐

  1. Atitit.如何建立研发体系

    Atitit.如何建立研发体系 组织,流程,prj..Mana  oppm 发管理是一个完整的管理体系,从结构上来讲,它主要由四个方面的内容构架而成:组织结构与岗位设置 管理流程与工作流程..项目及管 ...

  2. SSIS 包部署 Package Store 后,在 IS 中可以执行,AGENT 执行却报错

    可以执行 SSIS Package ,证明用 SSIS Package 的账户是可以执行成功的.SQL Server Agent 默认指定账号是 Network Service. 那么可以尝试一下将 ...

  3. 编写简单的Makefile文件

    makefile中的编写内容如下: www:hello.c x.h gcc hello.c -o hello clean: rm hello www:hello.c  x.h 表示生成www这个文件需 ...

  4. ubuntu14 安装及卸载vmware

    原帖http://blog.sina.com.cn/s/blog_73dac6b50101gp4f.html 适用于ubuntu14和vmware player 12.5

  5. 我的MYSQL学习心得(九) 索引

    我的MYSQL学习心得(九) 索引 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  6. 我的MYSQL学习心得(十七) 复制

    我的MYSQL学习心得(十七) 复制 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  7. EQueue文件持久化消息关键点设计思路

    要持久化的关键数据有三种 消息: 队列,队列中存放的是消息索引信息,即消息在文件中的物理位置(messageOffset)和在队列中的逻辑位置(queueOffset)的映射信息: 队列消费进度,表示 ...

  8. 关于VS2015支持编译Linux程序的问题

    现状 目前已经发布的VS2015中包括VS2015 Preview 以及 VS2015 CTP6,这两个版本均不支持直接编译C++代码为Linux程序,具体情况可以参考 Visual Studio 2 ...

  9. Hadoop2.2.0安装过程记录

    1    安装环境1.1    客户端1.2    服务端1.3    安装准备    2    操作系统安装2.1.1    BIOS打开虚拟化支持2.1.2    关闭防火墙2.1.3    安装 ...

  10. your password has expired.to log in you must change it

    今天应用挂了,log提示密码过期.客户端连接不上. 打开mysql,执行sql语句提示密码过期 执行set password=new password('123456'); 提示成功,但客户端仍然连接 ...