mongodb collection through webservice c# - asp.net

I am trying to return the results of monogdb query into a webapplication. The simplest initial one was just to return the full collection as you will see it in the mongodb console from a webservice call within the project that accesses the database:
> db.usercollection.find()
{ "_id" : ObjectId("52d2f2b3c60804b25bc5d2ca"), "username" : "testuser1", "email
" : "testuser1#testdomain.com" }
{ "_id" : ObjectId("52d2f2f9c60804b25bc5d2cb"), "username" : "testuser2", "email
" : "testuser2#testdomain.com" }
{ "_id" : ObjectId("52d2f2f9c60804b25bc5d2cc"), "username" : "testuser3", "email
" : "testuser3#testdomain.com" }
>
I would like to get the resulting json into an extjs grid. I am trying to ways to see if it works but the first question is actually how to return the result above:
<WebMethod()> _
<ScriptMethod(UseHttpGet:=True, ResponseFormat:=ResponseFormat.Json)> _
Public Function getDBData() As String
Dim response As String = String.Empty
mongo.Connect()
Dim db = mongo.GetDatabase("nodetest1")
Using mongo.RequestStart(db)
Dim collection = db.GetCollection(Of BsonDocument)("usercollection").FindAll()
response = collection.Collection.ToString
Return response
End Using
I am not seeing the result I want here:
var newStore = Ext.create('Ext.data.JsonStore', {
model: 'User',
proxy: {
type: 'ajax',
url: 'http://localhost:52856/WCFService/WebService1.asmx/getDBData',
reader: {
type: 'json',
root: 'd',
idProperty: '_id',
successProperty: 'success'
},
success: function (response, options) {
var s = response.responseText;
Ext.MessageBox.alert(s, 'LA LA LA');
newStore.loadData(s);
},
failure: function (response, options) {
Ext.MessageBox.alert('FAILED AGAIN', 'SUCKS');
}
}
});
I tried adding the root as follows:
response = "{""d"":" + response + "}"
Return response
The second alternative is to call the service from node.js directly but not show how to set up the result also:
Ext.Ajax.request({
url: 'http://localhost:3000/userlist',
method: 'GET',
success: function (response, options) {
var s = response.responseText;
Ext.MessageBox.alert(s, 'WOO WOO');
myStore.loadData(s);
},
failure: function (response, options) {
Ext.MessageBox.alert('FAILED MOFO', 'Unable to GET');
}
});
This is what I get back:
nodetest1.usercollection
View: userlist
extends layout
block content
h1.
User List
u1
each user, i in userlist
li
a(href="mailto:#{user.email}")= user.username
default route:
exports.index = function(db) {
return function(req, res) {
var collection = db.get('usercollection');
collection.find({},{}, function(e,docs){
res.render('userlist', {
"userlist" : docs
});
});
};
};
am I way off here or can someone see what I am doing wrong.

A call to FindAll returns a MongoCursor.
A quick way to convert that to a JSON format would be:
Return collection.ToArray().ToJSON()
You could loop through each result using a technique like this:
For Each document in collection
' do something with each document
Next document
Depending on the size of the results, you may find that returning the response uses a lot of server memory and takes a substantial amount of time to transmit and process in JavaScript.
Also, for production code, I'd recommend that the connection to MongoDB be only created once. The connection is thread safe and reusable (and uses a connection pool to support multiple clients). Opening and closing connections is "expensive."

Related

Cloud Task Creation : Error: 3 INVALID_ARGUMENT: Request contains an invalid argument

I'm following thist tutorial : https://cloud.google.com/tasks/docs/tutorial-gcf
To create a Task that would call a cloud function.
I've done quite some tries and still get this error:
If I change the body encoding to something else, I get another error about serialisation method.
It's likely not a permission issues, as I got some before and got rid of it.
The object which is pass to the createTask() is the following :
task: {
httpRequest: {
url: "https://europe-west1-project_id.cloudfunctions.net/FunctionName"
httpMethod: "POST"
oidcToken: {
serviceAccountEmail: "cf-targetFunctionSA#project_id.gserviceaccount.com"
}
body: ""
headers: {
Content-Type: "application/json"
}
}
(or with body: base64 encoded json string.)
The code I use is the following :
'use strict';
const common = require('./common');
const {v2beta3} = require('#google-cloud/tasks');
const cloudTasksClient = new v2beta3.CloudTasksClient();
let projectName = common.getProjectName();
let location = "europe-west3";
let queue = "compute-stats-on-mysql";
const parent = cloudTasksClient.queuePath(projectName, location, queue);
async function createTask(url, serviceAccount, data)
{
const dataBuffer = Buffer.from(JSON.stringify(data)).toString('base64');
const task = {
httpRequest: {
httpMethod: 'POST',
url:url,
oidcToken: {
serviceAccountEmail: serviceAccount,
},
headers: {
'Content-Type': 'application/json',
},
body:dataBuffer,
},
};
try
{
// Send create task request.
common.logDebug(`Before creating task`, {parent:parent,task:task, data:data});
const [response] = await cloudTasksClient.createTask({parent, task});
common.logDebug(`Created task ${response.name}`, {parent:parent,task:task, response:response, data:data});
return response;
}
catch (error)
{
// Construct error for Stackdriver Error Reporting
console.error("error while creating tasks",error);
}
}
module.exports = {
createTask : createTask,
cloudTasksClient:cloudTasksClient
};
The lack of details in the error makes me hit a wall blind...
Any suggestions ?
My service account was missing a part...
it was
"cf-"+functionName+"#"+projectName+".gserviceaccount.com";
instead of
"cf-"+functionName+"#"+projectName+".iam.gserviceaccount.com";
I left out the ".iam" during my numerous test to make it work.
For sure there's room for improvement in the error messages.
I had same problem. In your case I think there is not property scheduleTime into task param.
To me, the scheduleTime.seconds was with a wrong value.

Can't send data with $http.post in Ionic Framework

I'm trying make an application with Ionic framework which can take and send data to MS SQL server. For this I am using web api. I have no problem with taking data but something wrong with send new datas. Here is my ionic code :
angular.module('starter.controllers',[])
.controller('CheckListCtrl', function($scope, ChecklistService, $ionicPopup) {
function addCheck(){
ChecklistService.addCheck()
}
.factory('ChecklistService', ['$http', function ($scope, $http) {
var urlBase = 'http://localhost:56401/api';
var CityService = {};
CityService.addCheck = function(){
var url = urlBase + "/TBLCHECKLISTs"
var checkdata = {
AKTIF : true,
SIL : false,
KAYITTARIHI : Date.now(),
KULLANICIID : 3,
BASLIK : "Onur",
TAMAMLANDI : false,
TAMAMLANMATARIHI : null,
GUN : 1
}
var request = $http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: checkdata
});
return request;
}
return CityService;
}]);
And here is my web api:
[HttpPost]
[ResponseType(typeof(TBLCHECKLIST))]
public IHttpActionResult PostTBLCHECKLIST(TBLCHECKLIST tBLCHECKLIST)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
tBLCHECKLIST.KAYITTARIHI = DateTime.Now;
db.TBLCHECKLISTs.Add(tBLCHECKLIST);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = tBLCHECKLIST.TABLEID }, tBLCHECKLIST);
}
When i try to send i get this exception:
After, I realize that I take that exception because my checkdata is never come to web api. I don't know why.
These are not the datas I send:
I have tried different versions of post request but nothing. When I try to send data with PostMan, it works and I can insert data to my database. But why I can't do it with my application? Can anybody help me?
I think this should be the problem:
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
Try this:
return $http.post(url, checkdata);
And in your API:
[HttpPost]
[ResponseType(typeof(TBLCHECKLIST))]
public IHttpActionResult PostTBLCHECKLIST([FromBody]TBLCHECKLIST tBLCHECKLIST)
{
//code here
}
Also, make sure your checkdata properties match the ones in your TBLCHECKLIST c# type.

ASP.NET oData patchValue received from Angular is nothing

I'm developing an app with an Angular based front-end and an ASP.NET back end using oData and Oracle. I'm at the point where I'm trying to patch records on the back end. I'm using generic boilerplate code on the back end in my controller and the patch method looks like this:
<AcceptVerbs("PATCH", "MERGE")>
Async Function Patch(<FromODataUri> ByVal key As Decimal, ByVal patchValue As Delta(Of FTP_ORDERS)) As Task(Of IHttpActionResult)
Validate(patchValue.GetEntity())
If Not ModelState.IsValid Then
Return BadRequest(ModelState)
End If
Dim fTP_ORDERS As FTP_ORDERS = Await db.FTP_ORDERS.FindAsync(key)
If IsNothing(fTP_ORDERS) Then
Return NotFound()
End If
patchValue.Patch(fTP_ORDERS)
Try
Await db.SaveChangesAsync()
Catch ex As DbUpdateConcurrencyException
If Not (FTP_ORDERSExists(key)) Then
Return NotFound()
Else
Throw
End If
End Try
Return Updated(fTP_ORDERS)
End Function
On the Angular side, I'm using $resource based service to send the update. The code that calls the resource looks like this:
(new FTPOrderService({
"key": vm.ID,
"data": vm
}, vm))
.$patch()
.then(function (data) {
alert("Order Saved!");
},
function (error) {
debugger;
}
);
The service is defined with:
.factory('FTPOrderService', function ($resource) {
var odataUrl = '../odata/FTP_ORDERS';
var results = $resource('', {}, {
'patch': {
method: 'PATCH',
params: {
key: '#key',
},
url: odataUrl + '(:key)'
}
});
return results;
})
I've also tried:
(new FTPOrderService({
"key": vm.ID,
}, vm))
.$patch(vm)
.then(function (data) {
alert("Order Saved!");
},
function (error) {
debugger;
}
);
and get the same results.
I believe that I have configured angular to send the data properly with:
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.patch = {
'Content-Type': 'application/json;charset=utf-8'
};
}])
The debugger shows that I'm calling the URL with the appropriate key appended to it in parens and the request payload looks like this:
{key: "1239990990", data: {loading: false, selectedRow: {}, lineItems: [,…], orderId: "1239990990",…}}
data: {loading: false, selectedRow: {}, lineItems: [,…], orderId: "1239990990",…}
key: "1239990990"
Any idea of what I'm missing? There are numerous examples out there using direct calls to $http.post and a few for .patch, but nothing current using $resource.
I am not entirely sure what the cause of this issue was, but in tracing it, I did discover that intermittently an object was not being received by the patch method in .NET. The object I'm passing in is particularly heavy and what I was passing by default was actually heavier than what the ASP.NET side of the app requires. Adding code prior to the patch call to assemble an object that meets the requirements at a minimum level resolved the issue.

Collection2, insert using method, exception from unique constraint not caught

I create a new project:
$ mrt create sandbox
$ mrt remove autopublish
$ mrt add collection2
And use the following code to create a simple collection with a unique constraint on a key
SandBoxCollection = new Meteor.Collection('sandboxcoll', {
schema: new SimpleSchema({
title: {
type: String,
min: 3,
unique: true,
index: true
}
})
});
if (Meteor.isServer) {
Meteor.publish('sandboxpub', function() {
return SandBoxCollection.find();
});
}
if (Meteor.isClient) {
Meteor.subscribe('sandboxpub');
}
Meteor.methods({
create: function(doc) {
var docId = SandBoxCollection.insert(doc, {validationContext: 'create'}, function(err, res) {
if (err) {
throw new Meteor.Error(333, SandBoxCollection.simpleSchema().namedContext('create').invalidKeys());
}
return res;
});
return docId;
}
});
I set up a simple collection, pub/sub and a method that I can use for inserts.
Then I use the browser console to issue the following commands
Let's first create a document:
Meteor.call('create', {title: 'abcd01'}, function(e,r){
console.log(e ? e : r);
});
Now let's try inserting a duplicate directly using collection.insert():
SandBoxCollection.insert({title: 'abcd01'}, function(e,r) {
console.log('error: ');
console.log(e);
console.log('errorkeys: ');
console.log(SandBoxCollection.simpleSchema().namedContext().invalidKeys());
console.log('result: ');
console.log(r);
});
We can see a proper 333 error handled by the callback and logged to the console.
Now try inserting a duplicate using the method:
Meteor.call('create', {title: 'abcd01'}, function(e,r){
console.log(e ? e : r);
});
Notice that, unlike the direct insert, the method throws an uncaught exception! Furthermore, the error is thrown from our custom throw and it has error code 333.
Why is this not handled properly? What can I do to mitigate this so that I can do something with the error (notify the user, redirect to the original documents page etc)
As of February 2014, this is an enhancement request on collection2 issue tracker at https://github.com/aldeed/meteor-collection2/issues/59
The current workaround (on the server) is to catch the error separately and feed it into a custom Meteor.Error as in:
if (Meteor.isServer) {
Meteor.methods({
insertDocument: function(collection, document) {
check(collection, String);
check(document, Object);
var documentId = '',
invalidKeys = [];
function doInsert() {
documentId = SandboxProject.Collections[collection + 'Collection'].insert(document, {validationContext: collection + 'Context'});
}
try {
doInsert();
} catch (error) {
invalidKeys = SandboxProject.Collections[collection + 'Collection'].simpleSchema().namedContext(collection + 'Context').invalidKeys();
error.invalidKeys = invalidKeys;
throw new Meteor.Error(333, error);
}
return documentId;
}
});
}
Note: This is a generic insert method that takes the namespaced collection name as a parameter and a document. It is intended to be called from the client side with a callback function which returns either the result as a document id or an error object.

jquery ui autocomplete needs additional function

I have such autocomplete code:
$("input#PickupSpot").autocomplete({
source: function(request, response){
$.ajax({
url: "AjaxSearch.aspx",
dataType: "jsonp",
data: {
a: "getspots",
c: "updateSpotList",
q: request.term
},
success: function(){
alert("Success");
},
error: function (xhr, ajaxOptions, thrownError){
alert(xhr.status);
alert(thrownError);
}
});
}
});
When i try to get data Firebug shows an error: "updateSpotList is not defined".
I need to creat a function called updateSpotList to get response from the server. And the success alert is never invoked.
Why do i need this function? Maybe there are something defined in aspx? It is:
string response = "";
string callback = Request.QueryString["c"];
string action = Request.QueryString["a"];
string query = Request.QueryString["q"];
//Ensure action parameter is set
if(action != null && action.Equals("getspots")){
//Ensure query parameter is set
if (query != null && query.Length > 0){
SpotListRequest request = new SpotListRequest
{
FreeText = query,
Language = "sv-SE"
};
IEnumerable<Spot> spots = DataBridge.GetSpotList(null, null, query).OrderBy(i => i.FullName);
JavaScriptSerializer js = new JavaScriptSerializer();
string json = js.Serialize(spots.ToArray());
//Ensure callback parameter is set
if (callback != null && callback.Length > 0)
{
response = String.Format("{0}('{1}')", callback, json);
}
}
}
You can specify a URL as the source parameter, instead of the data parameter.
http://jqueryui.com/demos/autocomplete/#option-source
The plugin will make a request to your server, and you should return a JSON array looking like this:
[{label: "Name"}, {label: "Name 2"}]
Change your JavaScript code to this:
$("input#PickupSpot").autocomplete({
source: "AjaxSearch.aspx?a=getspots&c=updateSpotList"
});
The autocomplete plugin will append a parameter named term to the source URL, with the current value of the input element, so a request would be made to: "AjaxSearch.aspx?a=getspots&c=updateSpotList&term=test" if you wrote test in the input element.
On the server, you want to change q to term.

Resources