如何通过微信小程序 .net实现路由选择net的模拟

学会NI-DAQmx10个函数,解决80%的数据采集应用问题 - National Instruments
学会NI-DAQmx10个函数,解决80%的数据采集应用问题
NI-DAQmx入门指南系列旨在帮助用户了解NI-DAQmx编程的基础知识。 从使用Measurement & Automation Explorer (MAX)验证设备运行情况到使用LabVIEW编程数据采集应用,本系列将通过视频和文本教程为您逐一介绍。 本系列既适用于希望学习使用DAQ助手的初学者,也适合需要使用NI-DAQmx的高级功能的有经验用户。
1. NI-DAQmx:减少开发时间,提升系统系能
自NI-DAQmx发布以来,NI数据采集(DAQ)硬件用户一直在充分利用软件的诸多特性来节省开发时间,并提高数据采集应用程序的性能。
其中一个能节省大量开发时间的特性是NI-DAQmx应用程序编程接口(API),该接口适用于各种设备功能和设备系列。 也就意味着在一个多功能设备的所有功能都可通过同一功能集(模拟输入、模拟输出、数字I/O和计数器)进行编程。 而且,数字I/O设备和模拟输出设备也可由同一个功能集进行编程。 在LabVIEW中,多态机制使得这些都成为可能。 一个多态VI可接受多种数据类型,用于一个或多个输入和/或输出终端。 NI-DAQmx API对于所有可支持的编程环境都是一样的。 用户只需学习运用一个功能集,便可在多种编程环境下对大部分的NI数据采集硬件进行编程。
另一个能够提升开发体验的NI-DAQmx特性是DAQ助手。 这个工具可帮助用户无需编程,仅通过图形化界面配置各种简单或复杂的数据采集任务,即可创建应用。 此外,因为触发和/或时钟信号必须手动路由,因此通常很难实现同步性。而使用NI-DAQmx,这将变得轻而易举,NI-DAQmx可以在一个设备上不同的功能区域间以及在多个设备上自动进行信号路由。
使用NI-DAQmx搭建的数据采集应用将受益于NI-DAQmx这一专门针对最优化系统性能而设计的架构。 该架构以一个高效的状态模型为基础,去除了不必要的重复配置。 将这些系统占用去除后,配置和采集过程都得到了优化。 另外,由于内存映射寄存器的存在,单点I/O采样率可达到50 kS/s以上。
NI-DAQmx构架的另一个重要特性是。 NI-DAQmx的多线程性可实现同时进行多个数据采集操作,从而大大提高了多操作应用的性能, 同时极大地简化此类应用的编程。
用户只需学习几个函数,即可开始享受这些特性所带来的好处。 事实上, NI-DAQmx的10个函数提供了解决80%的数据采集应用问题的功能。 下面将详细介绍这些函数,帮助用户理解其功能及其所适用的应用类型。
注:本文档中引用的范例可在该中找到。
2. DAQ助手
Tools>>Create/Edit DAQmx Tasks [CVI]
Project>>Add New Item>>DAQmx Task [.NET]
DAQ助手可通过图形化界面让用户交互式地创建、编辑、运行NI-DAQmx虚拟通道和任务。 NI-DAQmx虚拟通道包含DAQ设备上的一个物理通道以及该物理通道的配置信息,比如输入范围和自定义缩放。 NI-DAQmx任务就是一个包含虚拟通道、定时、触发信息、以及其他与采集和生成相关的属性的集合。 下图显示了如何配置DAQ助手来实现有限应变测量。
下列文档描述了DAQ助手在LabVIEW、LabWindows/CVI以及.NET中的应用:
DAQ助手还可生成代码,用于配置和/或执行指定的采集或生成。 DAQ助手帮助和文档均描述了在LabVIEW中实现该操作的步骤。 下图显示的是DAQ助手一个实例及其自动生成的配置和LabVIEW代码范例。
DAQ助手提供的灵活性和/或性能有时无法满足某些数据采集应用。 这些应用可能需要以下简单但强大的NI-DAQmx函数。
3. NI-DAQmx创建虚拟通道
Library>>NI-DAQmx>>Channel Creation/Configuration [CVI]
Task.Channel.CreateChannel Property [.NET]
“NI-DAQmx创建虚拟通道”函数可创建一个虚拟通道并将其添加至任务, 也可用于创建多个虚拟通道并将其全部添加至任务。 如未指定任务,该函数将自动创建一个任务。 “NI-DAQmx创建虚拟通道”函数包含多个实例, 这些实例对应虚拟通道执行的具体测量或生成类型。
在LabVIEW中创建通道
下图显示的是“NI-DAQmx创建虚拟通道”VI四个不同实例的范例。
“NI-DAQmx创建虚拟通道”函数不同实例的输入端各不相同, 但某些输入对于大部分(即使不是全部)函数实例都是通用的。 例如,指定虚拟通道使用的物理通道(模拟输入和模拟输出)、线路(数字)或计数器需要同一个输入。 此外,模拟输入、模拟输出和计数器操作根据信号的最小和最大预估值使用最小值和最大值输入来配置和优化测量和生成。 此外,多种类型的虚拟通道可进行自定义扩展。 下列LabVIEW程序框图中,“NI-DAQmx创建虚拟通道”VI用于创建热电偶虚拟通道。
在.NET中创建通道
大部分NI-DAQmx .NET库中的类无法直接被初始化, 这些类被用作任务类的子对象。
这些类包含了某个特定通道类型的专用属性。 例如:计数器等属性只适用于计数器,且只能在CIChannel和CIChannel类中找到。 用户可在NI-DAQmx .NET类库中将下列通道类型与某个任务关联起来:
模拟输入通道—AIChannel类
模拟输出通道—AOChannel类
数字输入通道—DIChannel类
数字输出通道—DOChannel类
计数器输入通道—CIChannel类
计数器输出通道—COChannel类
任务类包含一个适用于六种通道类型的通道集合属性:AIChannels、AOChannels、DIChannels、DOChannels、CIChannels和COChannels。 用户可使用通道集合中任意一种创建通道的方法创建通道。
建立了一个新的“任务”对象后,通过调用“通道”类中相应的成员函数即可创建和分配AIChannel对象。 以下程序片段用于创建一个简单的模拟输入电压通道:
analogInTask = new Task();
AIChannel myC
myChannel = analogInTask.AIChannels.CreateVoltageChannel(
    "dev1/ai1", //The physical name of the channel
    "myChannel", //The name to associate with this channel
    AITerminalConfiguration.Differential, //Differential wiring
    -10, //-10v minimum
    10, //10v maximum
    AIVoltageUnits.Volts //Use volts
在C/C++中创建任务
DAQmxCreateTask()函数可用于创建任务,DAQmxCreateAIVoltageChan()函数则用于创建模拟输入电压通道。 关于创建不同测试类型的通道的信息,请查看NI-DAQmx C Reference Help。 以下程序片段是这两个函数的应用范例。
TaskHandle  taskHandle=0;
char        chan[256] = "Dev1/ai0";
float64     min = -10, max = 10;
DAQmxCreateTask("",&taskHandle);
DAQmxCreateAIVoltageChan(taskHandle, chan, "", DAQmx_Val_Cfg_Default, min, max, DAQmx_Val_Volts, NULL);
练习范例:
Digital - Finite Output.vi
Thermocouple - Continuous Input.vi
Write Dig Port
Cont Thrmcpl Samples-Int Clk
WriteDigPort
ContAcqThermocoupleSamples_IntClk
4. NI-DAQmx触发
Library>>NI-DAQmx>>Triggering [CVI]
Task.Triggers Property [.NET]
“NI-DAQmx触发”函数可用于对触发进行配置来执行指定操作。 常用的操作是开始触发和参考触发。 开始触发用于启动采集或生成, 参考触发则用于在一组采集样本中创建预触发数据结束后和后触发数据开始前的位置。 可对这两个触发进行配置,使其发生在数字边沿、模拟边沿、或模拟信号进入或离开窗口时。
在LabVIEW中创建触发
在下面的LabVIEW程序框图中,开始触发和参考触发均已通过“NI-DAQmx触发”VI进行配置,可发生在数字边沿上来进行模拟输入操作。
许多数据采集应用程序需要在一个设备上实现不同功能区域的同步(例如,模拟输出和计数器), 而其他的程序也需要在多个设备之间实现同步。 为了实现这些同步,触发信号必须在单个设备的不同功能区域间或在不同的设备间进行路由。 NI-DAQmx则可自动执行这些路由。 使用“NI-DAQmx触发”函数时,所有有效的触发信号均可作为源输入到函数中。 例如,在下面的“NI-DAQmx触发”VI中,设备2的开始触发信号可用作设备1的开始触发源,而无需进行任何显式路由。
在.NET中创建触发
创建“任务”对象和“通道”后,用户可以调用“任务.触发”集合中的方法将触发添加至任务中。 以下程序代码显示了创建“数字边沿开始触发”:
analogInTask = new Task();
DigitalEdgeStartTriggerEdge triggerEdge = DigitalEdgeStartTriggerEdge.R
analogInTask.AIChannels.CreateVoltageChannel( ... );
analogInTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("PFI0", triggerEdge);
基于发送至ConfigureDigitalEdgeTrigger函数的参数,设备会根据内部或外部的触发线判断是否存在上升或下降数字边沿,然后再开始采集数据。 上面的程序代码用于将设备配置为根据PFI 0判断上升数字边沿触发。
在C/C++中创建触发
DAQmxCfgDigEdgeStartTrig()函数可用于创建数字边沿开始触发。 关于创建其他不同的触发,请查看NI-DAQmx C Reference Help。 以下程序代码显示了如何使用该函数从PFI0接收数字开始触发信号并在该线路中寻找上升边沿。
char        startTrigger[256] = "Dev1/PFI0";
int         startEdge = 0; // rising edge
DAQmxCreateTask("",&taskHandle));
DAQmxCreateAIVoltageChan(taskHandle, chan, "", DAQmx_Val_Cfg_Default, min, max, DAQmx_Val_Volts, NULL);
DAQmxCfgDigEdgeStartTrig(taskHandle, startTrigger, startEdge);  
文档中介绍了更多关于借助NI-DAQmx使用“NI-DAQmx触发”函数来实现同步的信息。
练习范例:
Voltage - Finite Input.vi
Voltage - Continuous Input.vi
Acq-Int Clk-Dig Start&Ref
Cont Acq-Int Clk-Anlg Start
AcqVoltageSamples_IntClkDigStartAndRef
ContAcqVoltageSamples_IntClkAnalogStart
5. NI-DAQmx定时
Library>>NI-DAQmx>>Timing [CVI]
Task.Timing Property [.NET]
“NI-DAQmx定时”函数用于对硬件定时的数据采集操作进行定时配置, 包括指定操作是连续执行还是有限执行、选择采集或生成的样本数量以进行有限操作、以及需要时创建缓冲区。
对于需要采样定时(模拟输入、模拟输出和计数器)的操作,“NI-DAQmx定时”函数的采样时钟实例可用于设置采样时钟源和采样速率,采样时钟源可以是内部也可以是外部的信号源。 采样时钟能够控制采集或生成样本的速率。 每个时钟脉冲将启动任务中每个虚拟通道的样本采集或生成。
在LabVIEW中配置任务定时
下面的LabVIEW程序框图显示的是如何使用“NI-DAQmx定时”VI的“采样时钟”实例来配置使用外部采样时钟的连续模拟输出生成。
为了实现数据采集程序间的同步,定时信号必须以与触发信号同样的方式在一个设备的不同功能区域间或在多个设备间进行路由。 NI-DAQmx可自动完成这些路由。 所有有效的定时信号都可作为“NI-DAQmx定时”函数的源输入。 例如,在以下“DAQmx定时”VI中,设备的模拟输出采样时钟信号可用作模拟输入通道采样时钟的信号源,而无需进行任何显式路由。
文档中介绍了更多关于借助NI-DAQmx使用“NI-DAQmx定时”函数来实现同步的信息。
由于所测信号可提供定时,因此大多数计数器操作都不需要采样定时。 这些应用应使用“NI-DAQmx定时”函数的隐式实例。 在以下LabVIEW程序框图中,“NI-DAQmx定时”VI的隐式实例用于以指定的采样数量将缓冲脉冲宽度采集配置为有限值。
在.NET中配置任务定时
Channel.Timing.ConfigureSampleClock()函数用于配置采样时钟源、采样时钟速率,以及待采集或生成的采样数。 以下程序代码显示了根据连接至设备PFI 0的外部采样时钟创建一个连续采样。
analogInTask = new Task();
analogInTask.AIChannels.CreateVoltageChannel( ... );
analogInTask.Timing.ConfigureSampleClock(
"/Dev1/PFI0", // external clock source line or use "" for internal clock
10000, // expected rate of external clock or actual rate of internal clock
SampleClockActiveEdge.Rising, // acquire on rising or falling edge of ticks
SampleQuantityMode.ContinuousSamples, // continuous or finite samples
1000 // number of finite samples to acquire or used for buffer size if continuous
在C/C++中配置任务定时
DAQmxCfgSampClkTiming函数用于配置C或C++中的任务定时。 以下程序代码显示了该函数应用于一个10000赫兹的内部时钟的范例。
char        clockSource[256] = "";
float64     rate = 10000;
DAQmxCfgSampClkTiming(taskHandle, clockSource, rate, DAQmx_Val_Rising, DAQmx_Val_ContSamps, 1000);
某些数据采集设备针对数字I/O操作采用的是握手定时模式。 握手协议通过与外部设备进行定时信号的请求和确认交互来传输样本。 “NI-DAQmx定时”函数的握手实例可用于为数字I/O操作配置握手定时模式。
练习范例:
Voltage - Continuous Output.vi
Counter - Read Pulse Width and Frequency (Finite).vi
Cont Gen Volt Wfm-Ext Clk
Buff Semi-Period-Finite
ContGenVoltageWfm_ExtClk
MeasBuffered_SemiPeriodFinite
6. NI-DAQmx开始任务
Library>>NI-DAQmx>>Task Configuration/Control>>Start Task [CVI]
Task.Start Method [.NET]
在引言中我们提过,NI-DAQmx使用的状态模型已去除了不必要的重复配置,可实现更高的效率和最佳的性能。 该状态模型包含一个任务的五个状态。 关于每一个状态的详细信息可在NI-DAQmx帮助下的NI-DAQmx重要概念>>NI-DAQmx通道和任务>>NI-DAQmx任务>>任务状态模型中找到。
“NI-DAQmx开始任务”函数可以将一个任务显式转换成运行状态。 运行状态下,任务进行指定的采集和生成。 当“NI-DAQmx读取”函数运行而“NI-DAQmx开始任务”函数未运行时,任务将隐式转换成运行状态并自动启动。 这种隐式转换也会发生在“NI-DAQmx写入”函数在指定的自动开始输入驱动下运行但“NI-DAQmx开始任务”函数未运行时。
虽然不一定需要,但包含硬件定时的采集或生成的任务最好使用“NI-DAQmx开始任务”函数来显式启动。 而且,如果需要多次执行“NI-DAQmx读取”函数或“NI-DAQmx写入”函数(比如在一个循环中),则应使用“NI-DAQmx开始任务”函数。 否则任务会由于不断重复开始和停止而影响执行性能。 关于使用何时“NI-DAQmx开始任务”函数的详细信息,请查看。
在LabVIEW中开始任务
以下LabVIEW程序框图显示的是模拟输出生成仅包含单个软件定时的采样而无需使用“NI-DAQmx开始”函数的情况。
相反,下面的LabVIEW程序框图显示的是多次执行“NI-DAQmx读取”函数从计数器读取数据而必须使用“NI-DAQmx开始”函数的情况。
在.NET中开始任务
Start()函数用于在“任务”对象中开始任务。 下面的代码是Start()函数的一个使用范例。
analogInTask = new Task();
analogInTask.AIChannels.CreateVoltageChannel( ... );
analogInTask.Timing.ConfigureSampleClock( ... );
analogInTask.Start();
在C/C++中开始任务
DAQmxStartTask()函数可用于开始任务, 该函数的一个应用代码范例如下。
DAQmxStartTask(taskHandle);
练习范例:
Counter - Continuous Output.vi
Current - Continuous Input.vi
Dig Pulse Train-Cont
Cont 0-20mA Samps-Int Clk
GenDigPulseTrain_Continuous
ContAcq0_20mACurrentSamples_IntClk
7. NI-DAQmx读取
Library>>NI-DAQmx>>Read Functions [CVI]
ChannelReader Class [.NET]
“NI-DAQmx读取”函数可从指定的采集任务中读取样本。 针对不同的函数实例可选择不同的采集类型(模拟、数字、或计数器)、虚拟通道数量、采样数量和数据类型。 指定的采样数量从DAQ板卡上的FIFO传输到RAM中的PC缓存后,“NI-DAQmx读取”函数再将样本从PC缓存转移到应用程序开发环境(ADE)内存中。
在LabVIEW中读取数据
下图显示的是四个不同 “NI-DAQmx读取”VI实例的范例。
可读取多个采样的“NI-DAQmx读取”函数实例包括一个用于指定函数执行时每通道采样数的输入。 对于有限采集,将每通道采样数指定为-1,函数将等待所有请求的样本采集完毕,然后再对这些样本进行读取。 对于连续采集,如果将每通道采样数指定为-1,则函数执行时将读取当前缓存区中的所有样本。 在以下LabVIEW程序框图中,“NI-DAQmx读取”VI已进行配置,可从多个模拟输入虚拟通道读取多个采样,然后将数据以波形的方式返回。 而且,由于每通道采样数输入已设置为常数10,每次执行VI时将从每个虚拟通道读取10个样本。
在.NET中读取数据
读取NI-DAQmx .NET库需要使用读取器和流对象。 该编程模式与.NET Framework读取文件和网络I/O的方式相似。
DaqStream类包含与I/O相关的属性(如CurrentReadPosition)和获取原始I/O的方法。流属性用于获取某个指定任务相对应的DaqStream类实例。 用户无法直接获得DaqStream类的例程。
为了在NI-DAQmx库中进行读取,需要创建一个读取器实例,并在构造器中传递DaqStream类的实例。 然后调用读取器类上的方法来读取数据,代码如下所示:
analogInTask = new Task();
analogInTask.AIChannels.CreateVoltageChannel( ... );
//Create the reader and attach it to the stream
AnalogSingleChannelReader reader = new AnalogSingleChannelReader(analogInTask.Stream);
//Perform the read
double[] data = reader.ReadMultiSample(100);
在C/C++中读取数据
DAQmxReadAnalogF64()函数用于读取C或C++中的模拟输入任务的模拟数据。 更多有关读取函数的信息,请查看NI-DAQmx C Reference Help。 以下是使用该函数从单个通道中读取1000个采样的代码范例。
int numRead = 0;
DAQmxReadAnalogF64(taskHandle, , DAQmx_Val_GroupByScanNumber, data, 1000, &numRead, NULL);
练习范例:
Voltage - SW-Timed Input.vi
Digital - Finite Input.vi
One Sample
Read Dig Chan
AcqOneVoltageSample
ReadDigChan
8. NI-DAQmx写入
Library>>NI-DAQmx>>Write Functions [CVI]
ChannelWriter Class [.NET]
“NI-DAQmx写入”函数用于将样本写入指定的生成任务中。 针对不同的函数例程可选择不同的生成类型(模拟或数字)、虚拟通道数量、采样数量和数据类型。 “NI-DAQmx写入”函数将样本从应用程序开发环境(ADE)写入到PC缓存中。 然后这些样本从PC缓存传输到DAQ板卡FIFO以进行生成。
每个“NI-DAQmx写入”函数的实例包含一个自动开始输入,用于在任务没有显式启动时判定该函数是否隐式启动任务。 本文“NI-DAQmx开始任务”一节已介绍过,显式启动硬件定时的生成任务时应使用“NI-DAQmx开始任务”函数。 如果需要多次执行“NI-DAQmx写入”函数,则还应使用该函数来使性能最优化。
在LabVIEW中写入数据
下图显示的是四个不同 “NI-DAQmx写入”VI实例的范例。
下面的LabVIEW程序框图用于实现有限模拟输出生成,其中一个"False"布尔常量连接至“NI-DAQmx写入”VI的自动开始输出,这是由于该生成是硬件定时的。 “NI-DAQmx写入”VI已进行配置,可将一个通道的多个模拟输入数据样本以模拟波形的形式写入任务。
在.NET中写入数据
写入NI-DAQmx .NET库需要使用写入器和流对象。 该过程与上述数据读取过程相似。
执行写入操作需要创建一个写入器实例,并在构造器中传递DaqStream类的实例。 然后调用写入器类上的方法来写入数据,代码如下所示:
analogOutTask = new Task();
analogOutTask.AOChannels.CreateVoltageChannel( ... );
//Create the writer and attach it to the stream
AnalogSingleChannelWriter writer = new AnalogSingleChannelWriter(analogOutTask.Stream);
//Perform the write
double[] data = writer.WriteMultiSample(100);
在C/C++中写入数据
DAQmxReadAnalogF64()函数用于写入模拟数据。 更多关于写入其他数据形式的信息,请查看NI-DAQmx C Reference Help。 以下是写入1000个模拟数据样本的代码片段。
int written = 0;
DAQmxWriteAnalogF64(taskHandle, .0, DAQmx_Val_GroupByChannel, data, &written, NULL);
练习范例:
Voltage - Finite Output.vi
Digital - Finite Output.vi
Volt Update
Write Dig Chan
GenVoltageUpdate
WriteDigChan
9. NI-DAQmx结束前等待
Library>>NI-DAQmx>>Task Configuration/Control>>Wait Until Task Done [CVI]
Task.WaitUntilDone Method [.NET]
“NI-DAQmx结束前等待”函数用于等待数据采集完毕后结束任务。 该函数可用于确保停止任务前已完成指定的采集或生成。 一般情况下,“NI-DAQmx结束前等待”函数用于有限操作。 一旦该函数执行完毕,则表示有限采集或生成已完成,任务可在不影响操作的情况下停止。 此外,超时输入可用于指定最长等待时间。 如果采集或生成没有在该时间内完成,则函数将退出并生成一个相应错误。
在LabVIEW结束前等待
以下LabVIEW程序框图中的“NI-DAQmx结束前等待”VI用于确认有限数字输出完成后才将任务清除。
在.NET中结束前等待
更多关于在.NET中使用该函数的信息,请查看随附的GenMultVoltUpdates_IntClk范例。
在C/C++中结束前等待
DAQmxWaitUntilTaskDone()函数用于等待直至缓存区的所有样本均生成完毕。 该函数在写入或开始函数之后调用。
练习范例:
Digital - Finite Output.vi
Voltage - Finite Output.vi
Mult Volt Updates-Int Clk
GenDigPulse
GenMultVoltUpdates_IntClk
10. NI-DAQmx清除任务
Library>>NI-DAQmx>>Task Configuration/Control>>Clear Task [CVI]
Task.Dispose Method [.NET]
“NI-DAQmx清除任务”函数用于清除指定的任务。 如果任务正在运行,则函数将先停止任务,然后释放任务所有的资源。 一旦任务被清除后,除非再次创建,否者该任务无法再使用。 因此,如果需要再次使用任务,则应使用“NI-DAQmx停止任务”函数来停止任务,而不是将其清除。
对于连续操作,应使用“NI-DAQmx清除任务”函数来停止实际的采集或生成。
在LabVIEW中清除任务
在下面的LabVIEW程序框图中,连续脉冲序列通过计数器来生成。 脉冲序列将连续输出直至退出While循环,然后开始执行“NI-DAQmx清除任务”VI。
在.NET中清除任务
任务完成读取或写入后,调用Task.Dispose方法即可清除任务。
在C/C++中清除任务
任务完成读取或写入后,使用DAQmxClearTask()函数即可清除任务。
练习范例:
Voltage - Continuous Output.vi
Counter - Count Edges (Continuous Clock).vi
Cont Gen Volt Wfm-Int Clk
Cnt Dig Events
ContGenVoltageWfm_IntClk
CountDigEvents
11. NI-DAQmx属性
Attribute [CVI]
Property [.NET]
通过“NI-DAQmx属性”可以访问与数据采集操作相关的的所有属性。 这些属性可通过“NI-DAQmx属性”写入来进行设置,当前的属性值也可以通过“NI-DAQmx属性”读取。
前面我们已讨论过,许多属性可使用NI-DAQmx函数进行设置。 比如,采样时钟源和采样时钟有效边沿属性可通过“NI-DAQmx定时”函数进行设置。 然而,一些较少使用的属性只能通过“NI-DAQmx属性”来进行设置。
在LabVIEW中使用属性(属性节点)
在LabVIEW中,一个“NI-DAQmx属性节点”可用于写入和/读取多个属性。 例如,下面的“LabVIEW NI-DAQmx定时属性节点”先设置了采样时钟源, 然后读取采样时钟源, 最后设置采样时钟的有效边沿。
在下面的LabVIEW程序框图中,“NI-DAQmx通道属性节点”用于启用硬件低通滤波器,然后设置滤波器的截止频率以便进行应变计测量。
在.NET中使用属性
我们在“定时”部分已介绍过,许多属性是通过“任务”对象内部的子类和集合进行设置。 以下代码片段是NI-DAQmx属性使用的一个常见范例:
//Create a new NI-DAQmx Task
Task t = new Task();
//Access the subobject properties of the Task class
t.Timing.SamplesPerChannel = 1000;
在C/C++中使用属性
为了获取或设置任务的不同属性,每一个属性都有其相应的获取和设置函数。 如需了解更多信息,可在NI-DAQmx C Reference Help 下的NI-DAQmx C Reference Help中查看属性列表及其功能。
练习范例:
Strain - Continuous Input.vi
Thermocouple (with OTCD) - Continuous Input.vi
Cont Strain Samples
Cont Accel Samps-Int Clk-Anlg Start
AcqStrainSamples
ContAcqAccelSamp_IntClk_AnalogStart
NI-DAQmx可通过多种方式来帮助用户节省开发时间并提高数据采集应用的性能, 其中一种方式是提供仅需使用少量函数却可实现大部分功能的API。 事实上,用户只需学习本文介绍的10个函数,便可解决80%的数据采集应用问题。
书签收藏和分享
本网站使用cookies来为您提供更好的浏览体验。本博客由 nodejs + markdown 实现。
统计信息由 google analytics 提供。
评论使用多说评论插件。
Github 地址:。> 博客详情
摘要: 过去两年中,我最喜欢的一项技术就是设计单页面应用(SPA)的 AngularJS。作为一个微软stack开发者,我也是使用 ASP.NET MVC 平台实现 MVC 设计模式和并进行研究的粉丝,包括它的捆绑和压缩功能以及实现其对 RESTful 服务的 Web API 控制器。为了兼得两者,本文介绍了在 ASP.NET MVC 中集成 AngularJS 的两全其美的方案。
当涉及到计算机软件的开发时,我想运用所有的最新技术。例如,前端使用最新的 JavaScript 技术,服务器端使用最新的基于 REST 的 Web API 服务。另外,还有最新的数据库技术、最新的设计模式和技术。
当选择最新的软件技术时,有几个因素在起作用,其中包括如何将这些技术整合起来。过去两年中,我最喜欢的一项技术就是设计单页面应用(SPA)的 AngularJS。作为一个微软stack开发者,我也是使用 ASP.NET MVC 平台实现 MVC 设计模式和并进行研究的粉丝,包括它的捆绑和压缩功能以及实现其对 RESTful 服务的 Web API 控制器。
为了兼得两者,本文介绍了在 ASP.NET MVC 中集成 AngularJS 的两全其美的方案。
由于本文篇幅较长,故会分为3篇,分别进行介绍。
本文中示例的 Web 应用程序将有三个目标:
在前端页面中实现 AngularJS 和 JavaScript AngularJS 控制器
使用微软的 ASP.NET MVC 平台来建立、引导并捆绑一个应用
根据功能模型的需求,动态的加载 AngularJS 的控制器和服务
本文的示例应用程序将包含三个主要文件夹:关于联系和索引的主文件夹、允许你创建,更新和查询客户的客户文件夹、允许你创建,更新和查询产品的产品文件夹。
除了使用 AngularJS 和 ASP.NET MVC,这个应用程序也将实现使用微软的 ASP.NET Web API 服务来创建 RESTful 服务。微软的实体框架将用于生成并更新一个 SQL Server Express 数据库。
此应用程序也将用到一些使用 Ninject 的依赖注入。此外,也会运用流畅的界面和 lambda 表达式,来合并使用称为 FluentValidation的.NET 的小型验证库,用于构建驻留在应用业务层的验证业务规则。
AngularJS VS ASP.NET Razor 视图
几年来,我一直在使用完整的 Microsoft ASP.NET MVC 平台来开发 Web 应用程序。相比于使用传统的 ASP.NET Web 窗体的 postback&模型, ASP.NET MVC 平台使用的是 Razor 视图。 这带来的是:适当的业务逻辑、数据和表示逻辑之间关注点的分离。在使用它的约定优于配置和简洁的设计模式进行 MVC 开发之后,你将永远不会想回过头去做 Web 窗体的开发。
ASP.NET MVC 平台及其 Razor 视图引擎,不但比 Web 窗体简洁,还鼓励和允许你将 .NET 服务器端代码和样式混合。在 Razor 视图中的 HTML 混合的 .NET 代码看起来像套管代码。另外,在 ASP.NET MVC 模式下,一些业务逻辑是可以被最终写入在 MVC 的控制器中。在MVC控制器中,写入代码来控制表示层中的信息,这是很有诱惑力的。
AngularJS 提供了以下对微软 ASP.NET MVC Razor&视图的增强功能:
AngularJS 视图是纯 HTML 的
AngularJS 视图被缓存在客户端上以实现更快的响应,并在每次请求不产生服务器端响应
AngularJS 提供了一个完整的框架,编写高质量的客户端 JavaScript 代码
AngularJS 提供了&JavaScript 控制器和 HTML 视图之间的完全分离
ASP.NET MVC 捆绑和压缩
捆绑和压缩是两种你可以用来缩短 Web 应用程序的请求负载时间的技术。这是通过减少对服务器的请求数量和减小请求规模,来实现缩短请求负载时间的(如 CSS 和 JavaScript)。压缩技术通过复杂的代码逻辑也使得别人更难的侵入你的 JavaScript 代码。
当涉及到捆绑技术和 AngularJS 框架时,你会发现捆绑和压缩过程中会自动使用&Grunt&和&Gulp&之类的框架,Grunt&和 Gulp&技术是一种流行的 web 库并配有插件,它允许你自动化你的每一项工作。
如果你是一个微软开发者,你可以使用它们在 Visual Studio&中一键式发布你的 Web 应用,而不用学习使用任何第三发工具和库类。幸运的是,捆绑和压缩是 ASP.NET 4.5 ASP.NET 中的一项功能,可以很容易地将多个文件合并或捆绑到一个文件中。你可以创建 CSS,JavaScript 和其他包。较少的文件意味着更少的 HTTP 请求,这也可以提高第一个页面的加载性能。
使用 RequireJS 来实现 MVC 捆绑的动态加载
在开发 AngularJS 单页的应用程序时,其中有一件事情是不确定的。由于应用开始时会被引导和下载,所以在主页面索引时,AngularJS 会请求所有的 JavaScript 文件和控制器。对于可能包含数百个 JavaScript 文件的大规模应用,这可能不是很理想。因为我想使用 ASP.NET 的捆绑来加载所有的 AngularJS 控制器。一旦开始索引,一个 ASP.NET 捆绑中的巨大的挑战将会出现在服务器端。
为了实现示例程序动态地绑定 ASP.NET 文件包,我决定用 RequireJS&JavaScript 库。RequireJS 是一个众所周知的 JavaScript 模块和文件加载器,最新版本的浏览器是支持 RequireJS 的。起初,这似乎是一个很简单的事情,但随着时间的推移,我完成了大量的代码的编写,却并没有解决使用服务器端 rendered bundle 与客户端 AngularJS 等技术的问题。
最终,在大量的研究和反复试验和失败后,我想出了少量代码却行之有效的解决方案。
本文的接下来部分将会展示,在 ASP.NET MVC 中集成 AngularJS 的过程。
创建 MVC 项目并安装&Angular&NuGet 包
为了开始示例应用程序,我通过在 Visual Studio 2013 专业版中选择 ASP.NET Web 应用程序模板来创建一个 ASP.NET MVC 5 Web 应用程序。之后,我选择了 MVC 工程并在应用中会用到 MVC Web API 添加文件夹和引用。下一步是选择工具菜单中的“管理 NuGet 包的解决方案”,来下载并安装 NuGet AngularJS。
对于此示例应用程序,我安装了所有的以下的 NuGet 包:
AngularJS - 安装整个 AngularJS 库
AngularJS UI - AngularJS 框架的伙伴套件UI工具和脚本。
AngularJS UI引导 - 包含一组原生 AngularJS 指令的引导标记和CSS
AngularJS 块UI - AngularJS BlockUI 指令,块状化 HTTP 中的请求
RequireJS - RequireJS 是一个 JavaScript 文件和模块加载
Ninject – 提供了支持 MVC 和 MVC Web API 支持的依赖注入
实体框架 - 微软推荐的数据访问技术的新应用
流畅的验证 - 建立验证规则的 .NET 验证库。
优美字体- CSS 可立即定制的可升级的矢量图标
NuGet 是一个很好的包管理器。当你使用 NuGet 安装一个软件包,它会拷贝库文件到你的解决方案,并自动更新项目中的引用和配置文件。如果你删除一个包, NuGet 会让所有删除过程不会留下任何痕迹。
优美的URLS
对于此示例应用程序,我想在浏览器的地址栏中实现优美的网址。默认情况下,AngularJS 会将 URL 用#标签进行路由:
http://localhost:16390/
http://localhost:16390/#/contact
http://localhost:16390/#/about
http://localhost:16390/#/customers/CustomerInquiry
http://localhost:16390/#/products/ProductInquiry
通过转向&html5Mode&和设置基本的 URL,可以很方便的清除 URLS 并去除 URL 中的#。在 HTML5 模式下,AngularJS 的$位置服务会和使用 HTML5 History&API 的浏览器 URL 地址进行交互。HTML5 History API 是通过脚本来操作浏览器历史记录的标准方法,以这点为核心,是实现单页面应用的重点。
要打开 html5Mode,你需要在 Angular 的配置过程中,将 $locationProviderhtml5Mode 设置为 true,如下所示:
// CodeProjectRouting-production.js
angular.module("codeProject").config('$locationProvider', function ($locationProvider) {
$locationProvider.html5Mode(true);
当你使用 html5Mode 配置 $locationProvider 时,你需要使用 href 标记来指定应用的基本 URL。基本 URL 用于在整个应用程序中,解决所有相对 URL 的问题。你可以在应用程序中设置,如下所示的母版页的 header&部分的基本 URL:
&!-- _Layout.cshtml --&
&basehref="http://localhost:16390/"/&
对于示例应用程序,我以程序设置的方式将基本 URL 存储在 Web 配置文件中。这是一种最好的方式使得基本 URL 成为一种配置,这样能够让你根据环境、配置或者你开发的应用的站点的情况,来将基本 URL 设定为不同的值。此外,设置基本 URL 时,要确保基本 URL 以“/”为结尾,因为基本 URL 将是所有地址的前缀。
&!-- web.config.cs --&
&appsettings&
&addkey="BaseUrl"value="http://localhost:16390/"/&
&/appsettings&
打开 html5Mode 并设置基本 URL 后,你需要以以下优美的 URL 作为结束:
http://localhost:16390/
http://localhost:16390/contact
http://localhost:16390/about
http://localhost:16390/customers/CustomerInquiry
http://localhost:16390/products/ProductInquiry
目录结构与配置
按照惯例,一个 MVC 项目模板要求所有的 Razor&视图驻留在视图文件夹中;&所有的 JavaScript 文件驻留在脚本文件夹;&所有的内容文件驻留在内容文件夹中。对于此示例应用程序,我想将所有的 Angular&视图和相关的 Angular&JavaScript&控制器放入相同的目录下。基于 Web 的应用程序会变得非常大,我不想相关功能以整个应用程序的目录结构存储在不同文件夹中。
在示例应用程序,会出现两个 Razor&视图被用到,Index.cshtml 和 _Layout.cshtml 母版页布局,这两个 Razor&视图将用于引导和配置应用程序。应用程序的其余部分将包括 AngularJS 视图和控制器。
对于示例应用程序,我在视图文件夹下创建了两个额外的文件夹,一个客户的子文件夹,一个产品的子文件夹。所有的客户的 Angular 视图和控件器将驻留在客户子文件夹中,所有的产品的 Angular 视图和控件器将驻留在产品子文件夹中&。
由于 Angular&视图是 HTML 文件,而 Angular&控制器是 JavaScript 文件,从 Views 文件夹到浏览器,ASP.NET MVC 必须被配置为允许 HTML 文件和 JavaScript文 件进行访问和传递。这是一个 ASP.NET MVC 默认的约定。幸运的是,你可以通过编辑视图文件下的&web.config 文件并添加一个 HTML 和 JavaScript&的处理器来更改此约定,这将会使这些文件类型能够被送达至浏览器进行解析。
&!-- web.config under the Views folder --&
&system.webserver&
&handlers&
&addname="JavaScriptHandler"path="*.js"verb="*"precondition="integratedMode"
type="System.Web.StaticFileHandler"/&
&addname="HtmlScriptHandler"path="*.html"verb="*"precondition="integratedMode"
type="System.Web.StaticFileHandler"/&
&/handlers&
&/system.webserver&
应用程序版本自动刷新和工程构建
对于此示例应用程序,我想跟踪每一次编译的版本和内部版本号,在属性文件夹下使用&AssemblyInfo.cs&文件的信息测试并发布这个应用。每次应用程序运行的时候,我想获得最新版本的应用程序和使用的版本号,以实现最新的 HTML 文件和 JavaScript&文件生成时,帮助浏览器从缓存中,获取最新的文件来替换那些旧文件。
对于这种应用,我使用的 Visual Studio 2013 专业版,这让一切变得简单,我为 Visual Studio2013 专业版下载了一个自动版本的插件
它会自动刷新 C# 和 VB.NET 项目的版本。将安装插件下载到名为自动版本设置的工具菜单中。该插件自带了配置工具,它允许你配置主要和次要版本号,以便每次编译时,自动的更新 AssemblyInfo.cs 文件。目前,这个插件只是在 Visual Studio 2013 专业版中支持,或者你也可以手动更新版本号或使用类似微软的 TFS 以持续构建和配置管理环境的方式,来管理你的版本号。
下面是一个使用更新的 AssemblyVersion 和 AssemlyFileVersion 号的示例,这个示例在版本编译之后会通过插件自动地进行更新。
// AssemblyInfo.cs
using System.R
using pilerS
using System.Runtime.InteropS
[assembly: AssemblyTitle("CodeProject.Portal")]
[assembly: AssemblyProduct("CodeProject.Portal")]
[assembly: AssemblyCopyright("Copyright & 2015")]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1d9cf973-f876-4adb-82cc-ac4bdf5fc3bd")]
// Version information for an assembly consists of the following four values:
// Major Version
// Minor Version
// Build Number
// Revision
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion(".403")]
使用&Angular&视图和控制器更换联系我们和关于 Razor 视图
要想使用 MVC 工程,首先要做的事情之一就是使用 AngularJS 视图和控制器来更换联系我们和关于 Razor&视图。这是一个很好的起点来测试你的配置是否能够使 AngularJS&正常建立并运行。随后如果不需要这些页面,你可以删除关于和联系我们的视图和控制器。
AngularJS 的这种创建控制器的方式是通过注入&$scope&实现的。示例应用程序的视图和控制器使用“controller as”语法。此语法并非使用控制器中的 $scope,而是简化你的控制器的语法。当你声明一个“controller as”语法的控制器时,你会得到该控制器的一个实例。
使用“controller as”语法,你的所有的连接到控制器(视图模式)的属性必须以你视图的别名作为前缀。在下面的视图代码片段,属性标题前面就加上了“VM”的别名。
&!-- aboutController.js --&
&div ng-controller="aboutController as vm" ng-init="vm.initializeController()"&
&h4 class="page-header"&{{vm.title}}&/h4&
当控制器构造函数被调用时,使用“controller as”的语法,叫做“this”的控制器示例就会被创建。不需要使用 Angular 提供的 $scope 变量,你只需要简单的声明一个&vm&变量并分配“this”给它。所有被分配给 vm&对象的变量都会替换掉 $scope。有了分配给控制器功能的示例的变量,我们就可以使用这些别名并访问这些变量。
此外,所有示例应用程序中的控制器都是使用“use strict”JavaScript&命令以一种严格的模式运行的。这种严格模式可以更容易地编写“安全”的 JavaScript 代码。严格模式将此前“不严格的语法”变成了真正的错误。作为一个例子,在一般的 JavaScript 中,错误输入变量名称会创建一个新的全局变量。在严格模式下,这将抛出一个错误,因此无法意外创建一个全局变量。
// aboutController.js
angular.module("codeProject").register.controller('aboutController',
['$routeParams', '$location', function ($routeParams, $location) {
"use strict";
this.initializeController = function () {
vm.title = "About Us";
如前所述,在 MVC Razor 视图中使用 AngularJS&视图和控制器的优势之一,就是 Angular&提供了很好的机制来编写高质量的 JavaScript 模块、一种纯 HTML 视图和 JavaScript 控制器之间的完全分离的编码方式。你不再需要使用 AngularJS&双向数据绑定技术来解析浏览器的文件对象模型,这也就使得你能够编写单元测试的 JavaScript 代码。
作为一个注脚,您将在 aboutController 看到一个名为 register.controller 的方法。在本文的后面,你会看到注册方法是从哪儿来的和它用来做什么。
主页索引的 Razor 视图和 MVC 路由
ASP.NET MVC 中集成 AngularJS&的一件有趣的事情,就是应用程序实际上是如何启动和实现路由的。当你启动应用程序时,ASP.NET MVC 将会以如下默认的方式进入并查看路由表:
// RouteConfig.cs
using System.Collections.G
using System.L
using System.W
using System.Web.M
using System.Web.R
namespace CodeProject.Portal
publicclass RouteConfig
publicstaticvoid RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
应用开始时,以上外装配置的 MVC 路由表中的配置,会将应用路由到 MVC Home 主控制器,并执行主控制器中的索引方法。这样会以 MVC 默认工程模板的形式,将&Index.cshtml MVC Razor&视图传递到用户输出的主页面内容中。
这个应用程序的目标是使用 Angular&视图取代所有的 MVC 视图。但问题是,甚至在 AngularJS&被启动之前,主页的 Razor&视图索引就已经被执行和注入了&_Layout.cshtml&主页面中。
自从我决定,将主页面改为 AngularJS&视图,我就使用包含 AngularJS&ng-view&标签的&div&标签删除了索引&Razor&视图的所有内容。
&!-- Index.cshtml --&
&divng-view&&/div&
该 AngularJS ngView 标签是一个指令,能以一种将当前路由的模板渲染成主页面布局的方式补充&$route service。我有两个选择,要么直接嵌入 NG-View 代码到母版页 _Layout.cshtml 或使用 Razor 视图将它注入到母版页。我决定简单地从索引 Razor 视图中注入标签。本质上,索引 Razor&视图在应用程序的引导过程中被简单的使用,并且在应用程序启动后不会被引用。
一旦应用程序被引导并开始启动,AngularJS 将会执行自己的路由系统并以路由表中配置来执行自己的默认路由。基于这一点,我创建了一个单独 AngularJS index.html 和主页的 IndexController.js 文件。
&!-- Index.html --&
&divng-controller="indexController as vm"ng-init="vm.initializeController()"&
&h4class="page-header"&{{vm.title}}&/h4&
当视图加载时,索引&Angular 视图将会通过&ng-init&指令来执行索引控制器的初始化功能。
// indexController.js
angular.module("codeProject").register.controller('indexController',
['$routeParams', '$location', function ($routeParams, $location) {
"use strict";
this.initializeController = function () {
vm.title = "Home Page";
RouteConfig.cs
当开发一个 AngularJS&应用时,首先将会发生的一件事,就是你需要先开发一个像驻留在路由文件中的 CustomerInquiry 一样的页面
/Views/Customers/ CustomerInquiry&
当你在 HTML 页面寻找这个视图时,点击 Visual Studio 中的运行按钮来直接执行这个页面,MVC 将会执行并尝试去查找一个用于客户路由的 MVC 控制器和视图。将会发生的是,你会获得一个叫做找不到该路由的视图或控制器的错误。
你当然会遇到这个错误,因为/View/Customers/CustomerInquiry的路由是个 Angular&路由,而不是 MVC 路由。MVC 并不知道这个路由。如果你还想直接运行这个页面,则需要解决这一问题,给 MVC 路由表增加另外的路由以便告诉 MVC 将所有的请求路由到 MVC 主控制器,并渲染Razor&视图、通过路由引导这个应用。
由于我有三个视图文件夹,主文件夹、客户文件夹和产品文件夹,我增加了一下的 MVC 路由配置类以便将所有的请求路由到主/索引路由中。当应用程序运行时点击 F5,同样也会进入 MVC 路由表。就 Angular&和单页面如何运行而言,当你点击 F5 时,基本上就是重启了 AngularJS&应用。
有了这些额外的路由,现在就可以直接执行 AngularJS 路由了。你可以在 MVC 路由表中以一种通配符的路由来处理你的路由,但我更愿意使用明确的路由表,并使得 MVC 拒绝所有无效的路由。
要记住的基本的事情是,MVC 路由将会在 AngularJS 启动之前发生,一旦引导开始,AngularJS 将会接管所有以后路由请求。
// RouteConfig.cs
using System.Collections.G
using System.L
using System.W
using System.Web.M
using System.Web.R
namespace CodeProject.Portal
publicclass RouteConfig
publicstaticvoid RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "HomeCatchAllRoute",
url: "Home/{*.}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
routes.MapRoute(
name: "CustomersCatchAllRoute",
url: "Customers/{*.}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
routes.MapRoute(
name: "ProductsCatchAllRoute",
url: "Products/{*.}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
$ controllerProvider 和动态加载控制器
当示例应用程序启动时,该应用程序将会预加载应用程序的核心控制器和服务。这包括 Home 目录中的所有控制器和应用程序的共享服务。
此应用程序的共享服务,将在所有模块中执行- 包括一个 Ajax 服务和提醒服务。如前所述,此应用程序具有三个功能模块:基本的关于、联系我们和主页的模块、一个客户模块和产品模块。
由于此应用程序可随时间而增长,我不希望该在应用程序的配置和引导阶段中,预加载所有的功能模块。应用程序启动后,我仅希望当用户请求时,再加载这些控制器和产品模块。
默认情况下,AngularJS 被设计为预加载所有的控制器。一个典型的控制器看起来这样:
// aboutController.js
angular.module("codeProject").controller('aboutController',
['$routeParams', '$location', function ($routeParams, $location) {
"use strict";
this.initializeController = function () {
vm.title = "About";
如果在配置阶段之后,你尝试动态加载上述控制器,将会收到一个 Angular 错误。你需要做的是使用 $controllerProvider 服务器在配置阶段之后,动态地加载控制器。Angular 使用 $controllerProvider 服务来创建新的控制器。这种方法允许通过注册方法来实现控制器注册。
// aboutController.js
angular.module("codeProject").register.controller('aboutController',
['$routeParams', '$location', function ($routeParams, $location) {
"use strict";
this.initializeController = function () {
vm.title = "About";
上述有关控制器被修改为执行&$controllerProvider 的寄存器方法。为了使这种注册方法有效,必须在配置阶段配置这种注册。下面的代码片段在应用程序启动之后,使用了&$controllerProvider 来使注册方法有效。在下面的例子中,提供了一种用于注册和动态加载两个控制器和服务的注册方法。如果你愿意,也可以包括&Angular 全部库和指令的注册功能。
// CodeProjectBootStrap.js
(function () {
var app = angular.module('codeProject', ['ngRoute', 'ui.bootstrap', 'ngSanitize', 'blockUI']);
app.config(['$controllerProvider', '$provide', function ($controllerProvider, $provide) {
app.register =
controller: $controllerProvider.register,
service: $provide.service
以上是如何在 ASP.NET MVC 中集成 AngularJS 的第一部分内容,后续内容会在本系列的后两篇文章中呈现,敬请期待!
通过第一部分内容的学习,相信大家已经对实现在 ASP.NET MVC 中集成 AngularJS 的基本思路有所了解。当我们在进行 ASP.NET MVC 和 AngularJS 开始时,还可以借助开发工具来助力开发过程。ASP.NET MVC开发时,可以借助&&这一款轻量级控件,它与 Visual Studio 无缝集成,完全与 MVC6 和 ASP.NET 5.0 兼容,将大幅提高工作效率;AngularJS 开发时,可以借助&&这款为企业应用程序开发而推出的一系列包含 HTML5 和 JavaScript 的开发控件集,无论应用程序是移动端、PC端、还是必须要支持IE6,Wijmo 均能满足需求。
文章来源:By&Mark J. Caplin&
原文链接:/Articles/1033076/Integrating-AngularJS-with-ASP-NET-MVC
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥

我要回帖

更多关于 微信小程序 .net 的文章

 

随机推荐