模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C#间起着桥梁的作用。模型绑定的一个最简单的例子是带参数的控制器action方法,比如我们注册这样的路径映射:

routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);

控制器Home的Index action带有名为id的参数:

public ActionResult Index(int id) {
Person dataItem = personData.Where(p => p.PersonId == id).First();
return View(dataItem);
}

在我们请求URL“/Home/Index/1”时,默认action调用器ControllerActionInvoker使用模型绑定器为参数id赋值“1”。

默认模型绑定器

模型绑定器实现IModelBinder接口,MVC默认的模型绑定器类名为DefaultModelBinder。它从Request.form、RouteData.Values 、Request.QueryString、Request.Files查找参数值,比如上面例子中的参数id,它在下面路径中搜索:

  1. Request.Form["id"]
  2. RouteData.Values["id"]
  3. Request.QueryString["id"]
  4. Request.Files["id"]

模型绑定器使用参数的名称搜索可用值,一旦找到一个可以结果搜索即停止。

DefaultModelBinder在参数绑定中同时做类型变换,如果类型转换失败,参数绑定也失败,比如我们请求URL “/Home/Index/apple”会得到int类型不能null的错误,模型绑定器无法将apple转换成整数,视图将null赋值给id引发此错误。我们可以定义id参数为int?,这也只能解决部分问题,在Index方法内我们没有检查id为null的情况,我们可以使用默认参数来彻底解决:

...
public ActionResult Index(int id = ) {
Person dataItem = personData.Where(p => p.PersonId == id).First();
return View(dataItem);
}
...

实际的应用中我们还需要验证绑定的参数值,比如URL  /Home/Index/-1和 /Home/Index/500都可以成功绑定数值到id,但他们超过了集合的上下限。在类型转换时还必须注意文化语言差异,比如日期格式,我们可以使用语言无关的通用格式yyyy-mm-dd。

复杂类型的绑定

上面我们看到的都是绑定到简单c#类型的例子,如果要绑定的模型是类则要复杂的多。以下面的Model类为例:

 public class Person {
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public Address HomeAddress { get; set; }
public bool IsApproved { get; set; }
public Role Role { get; set; }
} public class Address {
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
} public enum Role {
Admin,
User,
Guest
}

创建两个CreatePerson控制器action来获取数据:

public ActionResult CreatePerson() {
  return View(new Person());
}
[HttpPost]
public ActionResult CreatePerson(Person model) {
  return View("Index", model);
}

这里的action方法参数为复杂类型Person,我们使用Html.EditorFor()帮助函数在视图中创建输入数据的HTML:

@model MvcModels.Models.Person
@{
ViewBag.Title = "CreatePerson";
}
<h2>Create Person</h2>
@using (Html.BeginForm())
{
<div>@Html.LabelFor(m => m.PersonId)@Html.EditorFor(m => m.PersonId)</div>
<div>@Html.LabelFor(m => m.FirstName)@Html.EditorFor(m => m.FirstName)</div>
<div>@Html.LabelFor(m => m.LastName)@Html.EditorFor(m => m.LastName)</div>
<div>@Html.LabelFor(m => m.Role)@Html.EditorFor(m => m.Role)</div>
<div>
@Html.LabelFor(m => m.HomeAddress.City)
@Html.EditorFor(m => m.HomeAddress.City)
</div>
<div>
@Html.LabelFor(m => m.HomeAddress.Country)
@Html.EditorFor(m => m.HomeAddress.Country)
</div>
<button type="submit">Submit</button>
}

使用强类型的EditFor函数能保证生成的HTML元素Name包含模型绑定需要的嵌套前缀,比如HomeAddress.Country,生成的HTML为:

...
<input class="text-box single-line" id="HomeAddress_Country" name="HomeAddress.Country" type="text" value="" />
...

自定义绑定名称前缀

有这样一种情况,我们根据一个对象类型生成HTML,但是希望结果绑定到另外一个对象类型,我们可以通过自定义绑定前缀来实现。比如我们的Model类:

public class AddressSummary {
public string City { get; set; }
public string Country { get; set; }
}

定义一个控制器方法来使用这个Model:

public ActionResult DisplaySummary(AddressSummary summary) {
return View(summary);
}

对应的DisplaySummary.cshtml视图也使用这个Model类:

@model MvcModels.Models.AddressSummary
@{
ViewBag.Title = "DisplaySummary";
}
<h2>Address Summary</h2>
<div><label>City:</label>@Html.DisplayFor(m => m.City)</div>
<div><label>Country:</label>@Html.DisplayFor(m => m.Country)</div>

如果我们从上面编辑Person的视图CreatePerson.cshtml提交到DisplaySummary action:

@model MvcModels.Models.Person
@{
ViewBag.Title = "CreatePerson";
}
<h2>Create Person</h2>
@using(Html.BeginForm("DisplaySummary", "Home")) {
<div>@Html.LabelFor(m => m.PersonId)@Html.EditorFor(m=>m.PersonId)</div>
<div>@Html.LabelFor(m => m.FirstName)@Html.EditorFor(m=>m.FirstName)</div>
<div>@Html.LabelFor(m => m.LastName)@Html.EditorFor(m=>m.LastName)</div>
<div>@Html.LabelFor(m => m.Role)@Html.EditorFor(m=>m.Role)</div>
<div>
@Html.LabelFor(m => m.HomeAddress.City)
@Html.EditorFor(m=> m.HomeAddress.City)
</div>
<div>
@Html.LabelFor(m => m.HomeAddress.Country)
@Html.EditorFor(m=> m.HomeAddress.Country)
</div>
<button type="submit">Submit</button>
}

DisplaySummary视图中将无法正确绑定City和Country,因为CreatePerson中City和Country的input元素名称包含HomeAddress前缀,提交的数据是HomeAddress.City和HomeAddress.Country,而DisplaySummary视图中是不需要这个前缀的。我们可以在控制器方法上通过Bind特性指定绑定前缀来修正:

public ActionResult DisplaySummary([Bind(Prefix="HomeAddress")]AddressSummary summary) {
return View(summary);
}

在Bind特性中我们还可以指定哪个属性不要绑定,比如:

public ActionResult DisplaySummary([Bind(Prefix="HomeAddress", Exclude="Country")]AddressSummary summary) {
return View(summary);
}

这里通过Exclude="Country"禁止Country属性的绑定,与此相对,可以通过Include来指定需要绑定的属性。Bind可以应用在单个action方法上,如果需要更大范围的效果,我们可以直接应用在模型类上:

[Bind(Include="City")]
public class AddressSummary {
public string City { get; set; }
public string Country { get; set; }
}

Bind可以同时应用在Model类和action方法上,一个属性只有在两个地方都没有被排除才会包含在绑定结果中。

绑定到数组和集合

DefaultModelBinder支持数组集合的绑定,比如下面的action方法使用数组作为参数:

public ActionResult Names(string[] names) {
names = names ?? new string[];
return View(names);
}

视图中我们创建一组同名的input元素:

@model string[]
@{
ViewBag.Title = "Names";
}
<h2>Names</h2>
@if (Model.Length == 0) {
using(Html.BeginForm()) {
for (int i = 0; i <; i++) {
<div><label>@(i + 1):</label>@Html.TextBox("names")</div>
}
<button type="submit">Submit</button>
}
} else {
foreach (string str in Model) {
<p>@str</p>
}
@Html.ActionLink("Back", "Names");
}

生成的HTML:

...
<form action="/Home/Names" method="post">
<div><label>1:</label><input id="names" name="names"type="text" value="" /></div>
<div><label>2:</label><input id="names" name="names"type="text" value="" /></div>
<div><label>3:</label><input id="names" name="names"type="text" value="" /></div>
<button type="submit">Submit</button>
</form>
...

提交数据时绑定器从多个names构建一个数组。

上面的例子换成集合是这样的:

public ActionResult Names(IList<string> names) {
names = names ?? new List<string>();
return View(names);
}

视图:

@model IList<string>
@{
ViewBag.Title = "Names";
}
<h2>Names</h2>
@if (Model.Count == 0) {
using(Html.BeginForm()) {
for (int i = 0; i <; i++) {
<div><label>@(i + 1):</label>@Html.TextBox("names")</div>
}
<button type="submit">Submit</button>
}
} else {
foreach (string str in Model) {
<p>@str</p>
}
@Html.ActionLink("Back", "Names");
}

如果是要绑定到一个自定义Model类型的集合:

public ActionResult Address(IList<AddressSummary> addresses) {
addresses = addresses ?? new List<AddressSummary>();
return View(addresses);
}

视图:

@using MvcModels.Models
@model IList<AddressSummary>
@{
ViewBag.Title = "Address";
}
<h2>Addresses</h2>
@if (Model.Count() == ) {
using (Html.BeginForm()) {
for (int i = ; i < ; i++) {
<fieldset>
<legend>Address @(i + )</legend>
<div><label>City:</label>@Html.Editor("[" + i + "].City")</div>
<div><label>Country:</label>@Html.Editor("[" + i + "].Country")</div>
</fieldset>
}
<button type="submit">Submit</button>
}
} else {
foreach (AddressSummary str in Model) {
<p>@str.City, @str.Country</p>
}
@Html.ActionLink("Back", "Address");
}

生成的HTML表单:

...
<fieldset>
<legend>Address </legend>
<div>
<label>City:</label>
<input class="text-box single-line" name="[0].City"type="text" value="" />
</div>
<div>
<label>Country:</label>
<input class="text-box single-line" name="[0].Country"type="text" value="" />
</div>
</fieldset>
<fieldset>
<legend>Address </legend>
<div>
<label>City:</label>
<input class="text-box single-line" name="[1].City"type="text" value="" />
</div>
<div>
<label>Country:</label>
<input class="text-box single-line" name="[1].Country"type="text" value="" />
</div>
</fieldset>
...

使用[0]、[1]作为输入元素的名称前缀,绑定器知道需要创建一个集合。

手工调用模型绑定

在请求action方法时MVC自动为我们处理模型绑定,但是我们也可以在代码中手工绑定,这提供了额外的灵活性。我们调用控制器方法UpdateModel手工绑定:

public ActionResult Address() {
IList<AddressSummary> addresses = new List<AddressSummary>();
UpdateModel(addresses);
return View(addresses);
}

我们可以提供UpdateModel额外的参数指定要数据提供者:

public ActionResult Address() {
IList<AddressSummary> addresses = new List<AddressSummary>();
UpdateModel(addresses, new FormValueProvider(ControllerContext));
return View(addresses);
}

参数FormValueProvider指定从Request.Form绑定数据,其他可用的Provider的还有RouteDataValueProvider(RouteData.Values)、QueryStringValueProvider(Request.QueryString)、HttpFileCollectionValueProvider(Request.Files),它们都实现IValueProvider接口,使用控制器类提供的ControllerContext作为构造函数参数。

实际上最常用的限制绑定源的方式是:

public ActionResult Address(FormCollection formData) {
IList<AddressSummary> addresses = new List<AddressSummary>();
UpdateModel(addresses, formData);
return View(addresses);
}

FormCollection为表单数据的键值集合,这是UpdateModel众多重载形式中的一种。

手工数据绑定的另外一个好处是方便我们处理绑定错误:

public ActionResult Address(FormCollection formData) {
IList<AddressSummary> addresses = new List<AddressSummary>();
try {
UpdateModel(addresses, formData);
} catch (InvalidOperationException ex) {
// provide feedback to user
}
return View(addresses);
}

另外一种处理错误的方式是使用TryUpdateModel:

public ActionResult Address(FormCollection formData) {
IList<AddressSummary> addresses = new List<AddressSummary>();
if (TryUpdateModel(addresses, formData)) {
// proceed as normal
} else {
// provide feedback to user
}
return View(addresses);
}

自定义Value Provider

除了上面看到的内建Value provider,我们可以从IValueProvider接口实现自定义的Value provider:

namespace System.Web.Mvc {
public interface IValueProvider {
bool ContainsPrefix(string prefix);
ValueProviderResult GetValue(string key);
}
}

模型绑定器调用ContainsPrefix方法确定value provider是否可以处理提供的名称前缀,GetValue根据传入的键返回可用的参数值,如果没有可用的数据返回null。下面用实例演示如何使用自定义value provider:

public class CountryValueProvider : IValueProvider {

        public bool ContainsPrefix(string prefix) {
return prefix.ToLower().IndexOf("country") > -;
} public ValueProviderResult GetValue(string key) {
if (ContainsPrefix(key)) {
return new ValueProviderResult("USA", "USA", CultureInfo.InvariantCulture);
} else {
return null;
}
}
}

CountryValueProvider处理任何包含country的属性,对所有包含country名称的属性总是返回“USA”。使用自定义value provider之前还需要创建一个工厂类来创建自动那个有value provider的实例:

public class CustomValueProviderFactory : ValueProviderFactory {

        public override IValueProvider GetValueProvider(ControllerContext controllerContext) {
return new CountryValueProvider();
}
}

最后把我们的类工厂在global.asax的application_start中添加到value provider工厂列表中:

public class MvcApplication : System.Web.HttpApplication {
protected void Application_Start() {
AreaRegistration.RegisterAllAreas(); ValueProviderFactories.Factories.Insert(, new CustomValueProviderFactory()); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}

这里使用ValueProviderFactories.Factories.Insert()将自定义的value provider工厂添加到列表首位以优先使用,当然也可以ValueProviderFactories.Factories.Add()添加到列表末尾。在注册使用这个value provider后,任何对country属性的绑定都会得到值USA。

自定义模型绑定器

除了自定义value provider,我们还可以从IModelBinder接口创建自定义的模型绑定器:

public class AddressSummaryBinder : IModelBinder {

        public object BindModel(ControllerContext controllerContext,  ModelBindingContext bindingContext) {

            AddressSummary model = (AddressSummary)bindingContext.Model ?? new AddressSummary();
model.City = GetValue(bindingContext, "City");
model.Country = GetValue(bindingContext, "Country");
return model;
} private string GetValue(ModelBindingContext context, string name) {
name = (context.ModelName == "" ? "" : context.ModelName + ".") + name; ValueProviderResult result = context.ValueProvider.GetValue(name);
if (result == null || result.AttemptedValue == "") {
return "<Not Specified>";
} else {
return (string)result.AttemptedValue;
}
} }

MVC调用AddressSummaryBinder的BindModel()方法获取模型类型的实例,这里简单的初始化一个AddressSummary实例,调用value provider获取对象属性值,在从value provider获取属性值时我们把添加模型名称ModelBindingContext.ModelName作为属性的前缀。同样,必须在application_start中注册自定义模型绑定器后才能使用:

...
ModelBinders.Binders.Add(typeof(AddressSummary), new AddressSummaryBinder());
...

Dependency Injection和依赖解决器

C#中使用接口可以帮助我们解耦构件, 获取接口的实现我们通常是直接初始化接口的一个实现类:

public class PasswordResetHelper {
  public void ResetPassword() {
    IEmailSender mySender = new MyEmailSender();
    //...call interface methods to configure e-mail details...
    mySender.SendEmail();
    }
}

使用IEmailSender接口在一定程度上PasswordResetHelper不再要求发送邮件时需要一个具体的邮件发送类,但是直接初始化MyEmailSender使得PasswordResetHelper并没有和MyEmailSender解耦开。我们可以把IEmailSender接口的初始化放到PasswordResetHelper的构造函数上来解决:

public class PasswordResetHelper {
  private IEmailSender emailSender;
  public PasswordResetHelper(IEmailSender emailSenderParam) {
    emailSender = emailSenderParam;
  }
  public void ResetPassword() {
    // ...call interface methods to configure e-mail details...
    emailSender.SendEmail();
  }
}

但这样带来的问题是如何获取IEmailSender的实现呢?这可以通过运行时Dependency Injection机制来解决,在创建PasswordResetHelper实例时依赖解决器提供一个IEmailSender的实例给PasswordResetHelper构造函数,这种注入方式又称为构造注入。依赖解决器又是怎么知道如何初始化接口的固实实现呢?答案是DI容器,通过在DI容器中注册接口/虚类和对应的实现类将两者联系起来。当然DI不只是DI容器这么简单,还必须考虑类型依赖链条、对象生命周期管理、构造函数参数配置等等问题,好在我们不需要编写自己的容器,微软提供自己的DI容器名为Unity(在nity.codeplex.com获取),而开源的Ninject是个不错的选择。Ninject可以在visual studio中使用nuget包管理器获取并安装,下面就以实例演示如何使用Ninject,我们从接口的定义开始:

using System.Collections.Generic;

namespace EssentialTools.Models {
public interface IValueCalculator { decimal ValueProducts(IEnumerable<Product> products);
}
}

接口的一个类实现:

using System.Collections.Generic;
using System.Linq; namespace EssentialTools.Models { public class LinqValueCalculator : IValueCalculator {
private IDiscountHelper discounter; public LinqValueCalculator(IDiscountHelper discounterParam) {
discounter = discounterParam;
} public decimal ValueProducts(IEnumerable<Product> products) {
return discounter.ApplyDiscount(products.Sum(p => p.Price));
}
}
}

我们创建一个使用Ninject的自定义依赖解决器:

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Ninject;
using EssentialTools.Models; namespace EssentialTools.Infrastructure {
public class NinjectDependencyResolver : IDependencyResolver {
private IKernel kernel; public NinjectDependencyResolver() {
kernel = new StandardKernel();
AddBindings();
} public object GetService(Type serviceType) {
return kernel.TryGet(serviceType);
} public IEnumerable<object> GetServices(Type serviceType) {
return kernel.GetAll(serviceType);
} private void AddBindings() {
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>(); }
}
}

这里最重要的是AddBindings方法中的kernel.Bind<IValueCalculator>().To<LinqValueCalculator>(),它将接口IValueCalculator和类实现LinqValueCalculator结合起来,在我们需要接口IValueCalculator的一个实例时,会调用NinjectDependencyResolver的GetService获取到LinqValueCalculator的一个实例。要使NinjectDependencyResolver起作用还必须注册它为应用默认的依赖解决器,这是在application_start中操作:

public class MvcApplication : System.Web.HttpApplication {
protected void Application_Start() {
AreaRegistration.RegisterAllAreas(); DependencyResolver.SetResolver(new NinjectDependencyResolver()); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); }
}

控制器的构造函数中我们传入接口IValueCalculator,依赖解决器会自动为我们创建一个LinqValueCalculator的实例:

public class HomeController : Controller {
private Product[] products = {
new Product {Name = "Kayak", Category = "Watersports", Price = 275M},
new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M},
new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M},
new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M}
};
private IValueCalculator calc; public HomeController(IValueCalculator calcParam) {
calc = calcParam;
} public ActionResult Index() {
ShoppingCart cart = new ShoppingCart(calc) { Products = products }; decimal totalValue = cart.CalculateProductTotal(); return View(totalValue);
}
}

Ninject的绑定方法非常的灵活:

kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 50M); //绑定时指定DefaultDiscountHelper的属性DiscountSize=50
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountParam", 50M);//绑定时指定DefaultDiscountHelper的构造函数参数discountParam=50
kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();//条件绑定,在注入到LinqValueCalculator时绑定接口LinqValueCalculator到FlexibleDiscountHelper

除了使用自定义的依赖解决器,我们可以从默认控制器工厂扩展控制器工厂,在自定义控制器工厂中使用Ninject依赖注入:

 public class NinjectControllerFactory : DefaultControllerFactory {
private IKernel ninjectKernel; public NinjectControllerFactory() {
ninjectKernel = new StandardKernel();
AddBindings();
} protected override IController GetControllerInstance(RequestContext
requestContext, Type controllerType) { return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
} private void AddBindings() {
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
}

MVC在获取控制器时调用GetControllerInstance,它使用ninjectKernel.Get(controllerType)来获取相应的控制类实例,同时解决构造注入的问题,比如HomeController的构造函数参数IValueCalculator calcParam,使用这种方式可以限制仅在控制器内注入,控制器外整个应用范围内我们仍然可以使用自定义依赖解决器注入。

需要注意的是依赖解决和注入不是模型绑定的一部分,但它们有一定的相似性,后者解决的action方法上的参数绑定,前者可以说是整个控制器类(构造函数)上的参数绑定(当然不只是用在控制器类上)。

以上为对《Apress Pro ASP.NET MVC 4》第四版相关内容的总结,不详之处参见原版 http://www.apress.com/9781430242369

ASP.NET MVC 4 (九) 模型绑定的更多相关文章

  1. [转]ASP.NET MVC 4 (九) 模型绑定

    本文转自:http://www.cnblogs.com/duanshuiliu/p/3706701.html 模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C ...

  2. ASP.NET MVC学习之模型绑定(1)

    一.前言 下面我们将开始学习模型绑定,通过下面的知识我们将能够理解ASP.NET MVC模型的模型绑定器是如何将http请求中的数据转换成模型的,其中我们重点讲述的是表单数据. 二.正文 1.简单类型 ...

  3. Asp.net Mvc 中的模型绑定

    asp.net mvc中的模型绑定可以在提交http请求的时候,进行数据的映射. 1.没有模型绑定的时候 public ActionResult Example0() { ) { string id ...

  4. ASP.NET MVC学习之模型绑定(2)

    3.手工调用模型绑定 很多情况下我们都是通过形参的方式接收来自http流中的数据,这看似是完美的,但是缺少了很多过程中的控制,所以我们就需要使用手工的方式进行绑定.下面我们通过一个例子来说明,首先打开 ...

  5. ASP.NET MVC中的模型绑定

    模型绑定的本质   任何控制器方法的执行都受action invoker组件(下文用invoker代替)控制.对于每个Action方法的参数,这个invoker组件都会获取一个Model Binder ...

  6. ASP.NET MVC 下自定义模型绑定,去除字符串类型前后的空格

    直接贴代码了: SkyModelBinder.cs using System.ComponentModel; using System.Linq; using System.Web.Mvc; name ...

  7. .NET MVC学习之模型绑定

    ASP.NET MVC学习之模型绑定(2)   继ASP.NET MVC学习之模型绑定继续 3.手工调用模型绑定 很多情况下我们都是通过形参的方式接收来自http流中的数据,这看似是完美的,但是缺少了 ...

  8. 【ASP.NET Core】MVC 控制器的模型绑定(宏观篇)

    欢迎来到老周的水文演播中心. 咱们都知道,MVC的控制器也可以用来实现 Web API 的(它们原本就是一个玩意儿),区别嘛也就是一个有 View 而另一个没有 View.于是,在依赖注入的服务容器中 ...

  9. ASP.NET MVC中的模型装配 封装方法 非常好用

    下面说一下 我们知道在asp.net mvc中 视图可以绑定一个实体模型 然后我们三层架构中也有一个model模型 但是这两个很多时候却是不一样的对象来的 就拿微软的官方mvc例子来说明 微软的视图实 ...

随机推荐

  1. win7 wamp 64位 php环境如何开启curl服务?

    这篇文章主要介绍了PHP简单开启curl的方法,较为详细的讲述了PHP开启curl函数库的具体步骤与相关注意事项,需要的朋友可以参考下 本文讲述了PHP简单开启curl的方法.分享给大家供大家参考,具 ...

  2. FTP和TCP的文件传输效率对比测试分析

    前言 最近因项目需要,需要把一定数量的中等文件从开发板上传到电脑上,分别选择了FTP和TCP自定义协议两种方式进行传输,进行了简单的对比测试,故做如下记录. 测试环境 开发板:Linux,ARMv7 ...

  3. Structured Streaming教程(2) —— 常用输入与输出

    上篇了解了一些基本的Structured Streaming的概念,知道了Structured Streaming其实是一个无下界的无限递增的DataFrame.基于这个DataFrame,我们可以做 ...

  4. Go语言之高级篇beego框架之model设计构造查询

    一.model设计构造查询 QueryBuilder 提供了一个简便,流畅的 SQL 查询构造器.在不影响代码可读性的前提下用来快速的建立 SQL 语句. QueryBuilder 在功能上与 ORM ...

  5. 技术分享:几种常见的JavaScript混淆和反混淆工具分析实战【转】

    信息安全常被描述成一场军备竞赛,白帽与黑帽,渗透测试者与黑客,善与恶,本文将聚焦这场永无止境决斗中的一个小点. HTML5 & JS 应用中充满着对输入进行验证/注入的问题,需要开发人员始终保 ...

  6. 《学习opencv》笔记——矩阵和图像操作——cvAnd、cvAndS、cvAvg and cvAvgSdv

    矩阵和图像的操作 (1)cvAnd函数 其结构 void cvAnd( //将src1和src2按像素点取"位与运算" const CvArr* src1,//第一个矩阵 cons ...

  7. Ubuntu16.04下安装和配置Redis

    一.前提条件 需要连接互联网,然后执行sudo apt-get update更新软件包 二.执行安装命令 sudo  apt-get install redis-server 执行后如下图所示,我们输 ...

  8. angularjs图片上传和预览 - ng-file-upload

    ng-file-upload ajax上传文件 官方demo地址 安装 bower install ng-file-upload-shim --save(for non html5 suppport) ...

  9. Window下对nodejs多版本管理GNVM

    Windows下对nodejs多版本的管理,实现随意切换! 官方地址: https://github.com/Kenshin/gnvm http://ksria.com/gnvm/ 01.下载GNVM ...

  10. [转]抛弃jQuery,使用原生JavaScript

    原文链接 Document Ready 事件 在jQuery中,document.ready可以让代码在整个文档加载完毕之后执行: $(document).ready(function() { // ...