In MVC 6 RCP 6 using Microsoft.AspNet.Security I was able to use a custom SecurityTokenValidator.
In RC Microsoft.AspNet.Security didn't exist in Beta4 so I changed my code to use Microsoft.AspNet.Authentication see below: (Compiles and runs but SecurityTokenValidator never fires.
services.Configure<ExternalAuthenticationOptions>(options =>
{
options.SignInScheme = OAuthBearerAuthenticationDefaults.AuthenticationScheme;
});
app.UseOAuthBearerAuthentication(options =>
{
options.TokenValidationParameters.ValidateAudience = true;
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.RequireSignedTokens = false;
options.AuthenticationScheme = OAuthBearerAuthenticationDefaults.AuthenticationScheme;
options.AutomaticAuthentication = true;
options.SecurityTokenValidators = new List<ISecurityTokenValidator> { validator };
});
Replace the app.UseOAuthBearerAuthentication code with
app.UseMiddleware<OAuthBearerAuthenticationMiddleware>(new ConfigureOptions<OAuthBearerAuthenticationOptions>(options =>
{
options.AutomaticAuthentication = true;
options.SecurityTokenValidators = new List<ISecurityTokenValidator> { validator };
}));
You got it?
Today occours that CustomSecurityValidationToken not fires because inner exception was throw (a inner validation occurs based in params in my case).
Try to debug Notifications and if it fires 'AuthenticationFailed', you will find in 'context' variable a Property named 'Exception' if any.
app.UseOAuthBearerAuthentication(bearer =>
{
bearer.SecurityTokenValidators = new List<ISecurityTokenValidator>() { new CustomSecurityValidationToken() };
bearer.AutomaticAuthentication = true;
bearer.Notifications = new OAuthBearerAuthenticationNotifications()
{
SecurityTokenReceived = context =>
{
return Task.FromResult(0);
},
MessageReceived = context =>
{
return Task.FromResult(0);
},
SecurityTokenValidated = context =>
{
return Task.FromResult(0);
},
AuthenticationFailed = context =>
{
context.Response.Redirect("Home/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
};
});
Related
I have this code snippet
Task.Run(async () =>
{
stream = await DependencyService.Get<IPicturePicker>().GetImageStreamAsync();
if (stream != null)
{
Device.BeginInvokeOnMainThread(() =>
{
ImageOne.Source = ImageSource.FromStream(() => stream);
ImageTwo.Source = ImageSource.FromStream(() => stream);
});
}
}
The problem with the code is that only ImageTwo.Source gets set (because it is the last one). How do I set both ImageOne and ImageTwo with the same stream? Is there a better way to do this then what i am doing?
Here is what you can do:
Device.BeginInvokeOnMainThread(async () =>
{
Stream stream = await DependencyService.Get<IPicturePicker>().GetImageStreamAsync();
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
image1.Source = ImageSource.FromStream(() => { return new MemoryStream(memoryStream.ToArray()); });
image2.Source = ImageSource.FromStream(() => { return new MemoryStream(memoryStream.ToArray()); });
});
Maybe you can get it doing this way:
Task.Run(async () =>
{
stream = await DependencyService.Get<IPicturePicker().GetImageStreamAsync();
if (stream != null)
{
Device.BeginInvokeOnMainThread(() =>
{
var source = ImageSource.FromStream(() => stream);
ImageOne.Source = source;
ImageTwo.Source = source;
});
}
}
You should test, I don't have tried it.
My case:
app.js:
let app = angular.module('myApp', []);
app.controller('login', function ($scope, $login) {
$scope.account = {};
$scope.loginForm_submit = function ($event, account) {
$event.preventDefault();
if ($login.isValid(account)) {
$login.submit(account);
// goal:
$login.submit(account).then(function () {
window.location = '/'
}, function (msg) {
console.log(msg)
});
}
};
});
login.js:
app.factory('$login', function () {
let o = {
isValid: function (x) {
let success = false;
// validating...
return success
},
submit: function (x) {
// prevent to force submitting
if (this.isValid(x)) {
let formData = new FormData(), xhttp = new XMLHttpRequest();
// appending data to 'formData' via 'x'...
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
let data = JSON.parse(xhttp.responseText);
if (data['Success']) {
// return then() with successCallback() function
} else {
let msg = data['ErrorMessage'];
// return then() with errorCallback() function
}
}
}
xhttp.open('POST', '/account/register');
xhttp.send(formData);
}
}
}
return o
});
data is an object like:
let data = {
'Success': false,
'ErrorMessage': 'Invalid login attempt.'
};
I want to return then() method after submitting to access result. How can I do that?
UPDATE:
In controller:
[HttpPost]
public async Task<ObjectResult> Login(LoginViewModel model)
{
IDictionary<string, object> value = new Dictionary<string, object>();
value["Success"] = false;
if (ModelState.IsValid)
{
// login
value["Success"] = true;
}
return new ObjectResult(value);
}
First of all, you should avoid using $ for your own functions.
About your problem, you need to use $q. And you should use what angular offers to you.
Let me give you this :
app.factory('loginFactory', function($q, $http) {
var ret = {
isValid: isValid,
submit: submit
}
return ret;
function isValid(x) {
// Your code ...
return false;
}
function submit(x) {
// x is your form data, assuming it's a JSON object
var deferred = $q.defer();
// Assuming you're posting something
$http.post('yoururl', x,{yourConfigAsAnObject: ''})
.then(function(success){
console.log(success.data);
deferred.resolve(success.data);
}, function(error) {
console.log(error);
deferred.reject(error);
});
return deferred.promise;
}
});
Now, in your controller, you can use
loginFactory.submit(yourParam).then(function(success){
// Your code
}, function(error) {
// Your code
});
app.factory('$login', function ($q) {
let o = {
isValid: function (x) {
let success = false;
// validating...
return success
},
submit: function (x) {
var d = $q.defer();
// prevent to force submitting
if (this.isValid(x)) {
let formData = new FormData(), xhttp = new XMLHttpRequest();
// appending data to 'formData' via 'x'...
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
let data = JSON.parse(xhttp.responseText);
if (data['Success']) {
// return then() with successCallback() function
d.resolve('success');
} else {
let msg = data['ErrorMessage'];
d.reject(msg);
// return then() with errorCallback() function
}
}
}
xhttp.open('POST', '/account/register');
xhttp.send(formData);
}
else {
d.reject('error');
}
return d.promise;
}
}
return o
});
dude,I made a sample function with promise
$q should be injected as dependency
class AppUserService {
constructor($http,CONFIG_CONSTANTS,$q, AuthService) {
this.API_URL = CONFIG_CONSTANTS.API_URL;
this.$http = $http;
this.$q = $q;
this.api_token = AuthService.api_token;
}
getAppUserList() {
const deferred = this.$q.defer();
this.$http.get(`${this.API_URL}/customer?api_token=${this.api_token}`)
.success(response => deferred.resolve(response))
.error(error => deferred.reject(error));
return deferred.promise;
}
}
its in ES6 form.
How to use:
AppUserService.getAppuserList().then(success => {
// code for success
},error => {
// code for error
})
submit: function (x) {
return $q(function (resolve, reject) {
// prevent to force submitting
if (this.isValid(x)) {
let formData = new FormData(), xhttp = new XMLHttpRequest();
// appending data to 'formData' via 'x'...
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
let data = JSON.parse(xhttp.responseText);
if (data['Success']) {
resolve(data);
// return then() with successCallback() function
} else {
let msg = data['ErrorMessage'];
reject(msg);
}
}
}
xhttp.open('POST', '/account/register');
xhttp.send(formData);
}
else
reject('x not valid');
}
}
}
But I recommended to use angular $http service.
I have this code on my meteor app:
// client side
Template.lead.events({
'submit .insertExternalAccountForm': function (event) {
event.preventDefault();
Session.set('mcsStatus', 'Creating external account ...');
var target = {
code: event.target.code.value,
leadId: event.target.leadId.value,
name: event.target.name.value,
username: event.target.username.value,
password: event.target.password.value,
searchSourceId: event.target.searchSourceId.value,
clientId: event.target.clientId.value,
clientUserId: event.target.clientUserId.value
};
var noFormError = true;
if (target.username.length === 0) {
Session.set("username_error", "Field must not be empty");
noFormError = false;
} else {
Session.set("username_error", null);
}
if (target.password.length === 0) {
Session.set("password_error", "password must not be empty");
noFormError = false;
} else {
Session.set("password_error", null);
}
if (!noFormError) {
return noFormError;
}
Meteor.call('createExternalAccount', target, function (err, res) {
if (err) {
console.error(err);
}
console.log('in meteor call');
Router.go('/' + res.domain + '/' + res.externalId);
});
}
});
//server side
var createExternalAccountSync = function (query, external) {
return models.SearchSources.findOne(query).exec()
.then(function (searchsource) {
external.domain = searchsource.source;
var emr = searchsource.source.split('-');
return models.Organization.findOne({externalId: emr[2]}).exec();
}).then(function (org) {
console.log('after org');
external.organizationId = org._id;
return models.AppUser.findOne({clientId: external.clientId, externalId: external.clientUserId }).exec();
}).then(function (user) {
console.log('after app user');
external.userId = user._id;
external.userIds = [user._id];
return new Promise(function (resolve,reject) {
console.log('saveOrUpdate');
models.ExternalAccount.saveOrUpdate(external, function (err, newE) {
if (err) {
console.error(err)
reject(err);
}
resolve(newE)
});
});
})
.catch(function (e) {
console.error(e);
throw new Meteor.Error(e);
});
};
Meteor.methods({'createExternalAccount': function (data) {
var query = {};
var newExternalAccount = new models.ExternalAccount();
newExternalAccount.username = data.username;
newExternalAccount.password = data.password;
newExternalAccount.externalId = data.username;
newExternalAccount.name = data.name;
newExternalAccount.clientId = data.clientId;
newExternalAccount.clientUserId = data.clientUserId;
newExternalAccount._metadata = { leadId: data.leadId };
if (data.code === 'f') {
query.searchSourceId = '5744f0925db77e3e42136924';
} else {
query.searchSourceId = data.searchSourceId;
}
newExternalAccount.searchSourceId = query.searchSourceId;
console.log('creating external account')
createExternalAccountSync(query, newExternalAccount)
.then(function (external) {
console.log('should return to meteor call');
return external;
})
.catch(function (e) {
console.error(e);
throw new Meteor.Error(e);
});
}
});
The problem that I'm having is that the code on the server side, while it's being called properly, is not triggering the client side meteor.call, there's no console.log output or anything. I believe that the Meteor.wrapAsync method is properly used, but still not showing anything on the client side, and not in fact redirecting where I want the user to go after form submission.
UPDATE
The code has being updated to the newest form, but now I'm getting a weird error on the client, and its actually because the meteor.call method on the template returns neither error or result
Exception in delivering result of invoking 'createExternalAccount': http://localhost:3000/app/app.js?hash=c61e16cef6474ef12f0289b3f8662d8a83a184ab:540:40
http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:1105:27
_maybeInvokeCallback#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:3557:21
receiveResult#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:3577:30
_livedata_result#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:4742:22
onMessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:3385:28
http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:2736:19
forEach#[native code]
forEach#http://localhost:3000/packages/underscore.js?hash=27b3d669b418de8577518760446467e6ff429b1e:149:18
onmessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:2735:15
dispatchEvent#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:175:27
_dispatchMessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:1160:23
_didMessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:1218:34
onmessage#http://localhost:3000/packages/ddp-client.js?hash=27502404fad7fc072e57e8b0b6719f40d92709c7:1365:28
By the code you provided,it could be because you are calling different method.
You defined 'createAccount' but on client side you are calling 'createExternalAccount'
I try to implement a logIn in Meteor 0.9.2.1 with LDAPJS and Meteor methods. The code for the server-side is:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
LDAP = {};
LDAP.ldap = ldap;
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
LDAP.searchQuery = function(user) {
return{
filter: '(uid=username)',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
search.on('searchEntry', function(entry){
//console.log('entry: ' + JSON.stringify(entry.object));
dn.push(entry.object.uid);
dn.push(entry.object.userPassword)
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
var testBind = LDAP.ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
testBind.bind(dn[10], options.password, function (err) {
future['return'](!err);
});
client.unbind(function (err) {
assert.ifError(err);
future['return'](!err);
});
});
});
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
var loginHandler = function (username, password) {
Accounts.registerLoginHandler("ldapjs",function(loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var user = Meteor.users.findOne({ username: loginRequest.username });
if(err){
console.log(err)
}
return {
userId: uid
}
}
});
};
Meteor.methods({
setSignIn: function(username, password) {
loginHandler(username,password)
}
});
My Problem is, that when I want to log in it starts with the loginHandler. But than the console throws back that Object has no method checkAccount. I changed today a lot and I'm already totally confused.
You need to instantiate the empty object as var LDAP = {}. Rest will be solved magically :)
I finally got to work it. Referneces:
http://notjoshmiller.com/using-ldaps-in-meteor/, https://github.com/emgee3/meteor-accounts-ldap
server-side:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
var LDAP = {};
LDAP.ldap = ldap;
//provides the variables, needed for the connection
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
//is needed for the searchQuery, which delivers the Filter so that only the uid with
//the given username get searched
LDAP.searchQuery = function(username) {
return{
filter: '(uid=' + username + ')',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
//connects the client, nginx is here not necessary
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
//create the connection
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
if(err){
console.log(err)
}
//uses the class searchEntry, which is node-specific
search.on('searchEntry', function (entry) {
dn.push(entry.objectName);
LDAP.displayName = entry.object.displayName
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
//uses the end class to 'fulfill' the connection by binding
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
LDAP.client.bind(dn[0], options.password, function (err) {
future['return'](!err);
});
});
});
return future.wait();
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
Meteor.startup(function(){
Accounts.registerLoginHandler("ldapjs", function (loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var userId;
var user = Meteor.users.findOne({
username : loginRequest.username
//'profile.name': LDAP.displayName
});
if (user) {
userId = user._id;
} else {
// If no Meteor Account is found for a valid LDAP logon,
// you can either prevent logon by passing 'undefined' or
// you can automatically create the new account.
// return undefined;
userId = Meteor.users.insert({ username : loginRequest.username });
}
return {
userId: userId
}
}
return undefined;
});
});
client side:
Meteor.ldapLogin = function (username, password, callback) {
var loginRequest = {
username: username,
password: password
};
Accounts.callLoginMethod({
methodArguments: [loginRequest],
userCallback: function (err) {
if (err) {
console.log(err);
Session.set('alert', 'No valid inputs!');
} else {
Router.go('/Home');
}
}
});
};
//handles LogIn-Button, by using LDAPJS
Template.signIn.events({
"submit #box-login": function (e, t) {
e.preventDefault();
var signInForm = $(e.currentTarget),
username = trimInput(signInForm.find('#emailSignIn').val().toLowerCase()),
password = signInForm.find('#passwordSignIn').val();
if(isNotEmpty(username)&& isNotEmpty(password)) {
Meteor.ldapLogin(username, password, function (err) {
if (err) {
console.log(err)
Session.set('alert', 'Sorry, something went wrong.');
}
});
} else {
Session.set('alert','Please insert your username and password!')
}
return false;
}
});
PS: No Meteor.methods and Meteor.call is needed! It might change with every new Meteor version and package, but I guess u're aware of that ;)
I am beginner in using nopCommerce 2.30 (MVC 3 Razor) and Telerik().Grid. I am currently working
on Nop.Admin project.I try to create a Html.Telerik().Grid in my form, with many features.
Please see my grid image below.
These are the features.
grid data should be filter the selected value of the dropdownlist.
all grid columns are enable sorting.
in first column header contains a checkbox,for multiselect.
grid view must enable a column context menu.
Please see my code below.
My .cshtml file
<td>
#(Html.Telerik().Grid<NotificationMailReminderModel>()
.Name("productvariants-grid")
.DataKeys(keys =>
{
keys.Add(pv => pv.Username);
})
.DataBinding(dataBinding =>
dataBinding.Ajax()
.Select("EmailReminderByEvent", "Customer")
)
.Columns(columns =>
{
columns.Bound(pv => pv.IsSelected)
.ClientTemplate("<input type='checkbox' name='Id' value='<#= Id #>' />")
.HeaderTemplate(#<text><input type="checkbox" title="check all records" id="checkAllRecords" /></text>)
.Width(50)
.HeaderHtmlAttributes(new { style = "text-align:center" })
.HtmlAttributes(new { style = "text-align:center" });
columns.Bound(pv => pv.Username).ReadOnly().Width(250);
columns.Bound(pv => pv.Firstname).ReadOnly();
columns.Bound(pv => pv.Lastname).ReadOnly();
})
.ClientEvents(events => events.OnDataBinding("Grid_onDataBinding").OnError("Grid_onError").OnSubmitChanges("Grid_onSubmitChanges")
.OnRowDataBound("onRowDataBound"))
.Editable(editing => editing.Mode(GridEditMode.InCell))
.Pageable(settings => settings.PageSize(2).Position(GridPagerPosition.Both))
.Sortable(sorting => sorting.Enabled(true))
)
<script type="text/javascript">
$(document).ready(function () {
$('#search-products').click(function () {
var grid = $('#productvariants-grid').data('tGrid');
grid.currentPage = 1; //new search. Set page size to 1
grid.ajaxRequest();
return false;
});
$('#send-mail-reminder').click(function () {
var grid = $('#productvariants-grid').data('tGrid');
grid.ajaxRequest();
return false;
});
$('#grdCustomerEventRoleData #productvariants-grid table thead #checkAllRecords').click(function () {
$("#grdCustomerEventRoleData #productvariants-grid table tbody input:checkbox").attr("checked", this.checked);
});
});
function Grid_onError(args) {
if (args.textStatus == "modelstateerror" && args.modelState) {
var message = "Errors:\n";
$.each(args.modelState, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
args.preventDefault();
alert(message);
}
}
function Grid_onDataBinding(e) {
var loadData = true;
var grid = $(this).data('tGrid');
if (loadData) {
var searchModel = {
Event: $('#select-event').val()
};
e.data = searchModel;
}
}
function Grid_onSubmitChanges(e) {
//TODO pass current search parameters
//we can't pass search parameters in submit changes
//that's why let's just clear search params
//$('##Html.FieldIdFor(model => model.Event)').val('');
//$('#SearchCategoryId').val('0');
//$('#SearchManufacturerId').val('0');
}
</script>
</td>
My Controller actions
public ActionResult EmailReminder()
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers))
return AccessDeniedView();
var model = new NotificationMailReminderModels();
model.Event = 0;
List<Nop.Core.Domain.Catalog.Product> products = _productRepository.Table.Where(p => p.EventDate != null && p.EventDate >= DateTime.MinValue).OrderBy(o => o.Name).ToList();
model.Events = products.Select(p => new System.Web.Mvc.SelectListItem
{
Text = p.Name.Trim(),
Value = p.Id.ToString()
}).ToList();
return View(model);
}
[HttpPost, GridAction(EnableCustomBinding = true)]
public ActionResult EmailReminderByEvent(int[] Id, GridCommand command, NotificationMailReminderModels model)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageCustomers))
return AccessDeniedView();
var gridModel = new GridModel();
string vwSlEv = ViewBag.SelectedEvent;
int selevent = 0;
if (!string.IsNullOrEmpty(vwSlEv))
{
Int32.TryParse(vwSlEv, out selevent);
}
else
{
selevent = model.Event;
}
var csts = _customerEventRoleRepository.Table.Where(e => e.EventId == selevent).Select(cs => cs.CustomerId).Distinct().ToArray();
var customers = _customerRepository.Table.Where(c => !string.IsNullOrEmpty(c.Username) && !string.IsNullOrEmpty(c.Email) && csts.Contains(c.Id)).ToList();
var gridmodel = customers.Select(x =>
{
NotificationMailReminderModel not = new NotificationMailReminderModel();
not.Id = x.Id;
not.Username = x.Username;
not.Firstname = x.CustomerAttributes.FirstName;
not.Lastname = x.CustomerAttributes.LastName;
return not;
});
var grddata = new PagedList<NotificationMailReminderModel>(gridmodel.ToList(), command.Page - 1, command.PageSize);
gridModel.Data = grddata;
gridModel.Total = grddata.TotalCount;
return new JsonResult
{
Data = gridModel
};
}
data grid sorting and filtering works fine in my grid. But i can't get the ContextMenu
function in the Razor intellisence.
I want to passing the selected rows to the Controller POST function.
But, How to pass the selected rows in to the controller function.
please help.
But, How to pass the selected rows in to the controller function.
JQuery (Sample Code)
var MyConnectionList = {
ColorList: []
};
function SendStream() {
debugger;
MyConnectionList.ColorList.push({
"Name": 'Test1',
"Color": 'red'
});
MyConnectionList.ColorList.push({
"Name": 'Test2',
"Color": 'Green'
});
$.ajax({
url: "Ur url",
data: JSON.stringify(MyConnectionList),
type: 'POST',
contentType: 'application/json',
dataType: 'json',
success: function (data) { }
});
}
Action Method
public ActionResult SendStream(List<Sample> ColorList)
{
}