Javascript ServiceStack Client serialization error - javascript

So I have a master/detail scenario between two views. The master page shows a list and after clicking on one of the items, I send a message via the EventAggregator in Aurelia to the child view with a deserialized dto (coming from the selected item of the master) as a payload of the message.
However when I then try to pass this item as a parameter of a subsequent request in the child (to get additional info) the payload object fails to serialize.
Master.ts:
import { JsonServiceClient } from "servicestack-client";
import {
ListPendingHoldingsFiles,
ListPendingHoldingsFilesResponse,
SendHoldings,
PositionFileInfo
} from "../holdingsManager.dtos";
import { inject, singleton } from "aurelia-framework";
import { Router } from "aurelia-router";
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
#singleton()
#inject(Router, EventAggregator)
export class Pending {
router: Router;
positions: PositionFileInfo[];
client: JsonServiceClient;
eventAgg: EventAggregator;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.client = new JsonServiceClient('/');
var req = new ListPendingHoldingsFiles();
this.client.get(req).then((getHoldingsResponse) => {
this.positions = getHoldingsResponse.PositionFiles;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
openHoldings(positionInfo) {
this.eventAgg.publish(new GetPendingPositionMessage(positionInfo));
this.router.navigate('#/holdings');
}
}
Child.ts:
import { JsonServiceClient } from "servicestack-client";
import { inject, singleton } from "aurelia-framework";
import { Router } from 'aurelia-router';
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
import {
GetPendingHoldingsFile,
GetPendingHoldingsFileResponse,
Position,
PositionFileInfo
} from "../holdingsManager.dtos";
#singleton()
#inject(Router, EventAggregator)
export class Holdings {
router: Router;
pendingPositionFileInfo: PositionFileInfo;
position: Position;
client: JsonServiceClient;
eventAgg: EventAggregator;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.eventAgg.subscribe(GetPendingPositionMessage,
message => {
this.pendingPositionFileInfo = message.fileInfo;
});
}
activate(params, routeData) {
this.client = new JsonServiceClient('/');
var req = new GetPendingHoldingsFile();
req.PositionToRetrieve = this.pendingPositionFileInfo;
this.client.get(req).then((getHoldingsResponse) => {
this.position = getHoldingsResponse.PendingPosition;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
}
So the error happens when the child activates and attempts to send the request 'GetPendingHoldingsFile'.
Failed to load resource: the server responded with a status of 500 (NullReferenceException)
I have verified that this.pendingPositionFileInfo in the child is not null or empty and that on the server side, the object is not being received (it is null). I am new to Aurelia and not very experienced with Javascript so I must be missing something, any advice would be appreciated.
Edit 1
This seems to be something wrong with how I'm interacting with ServiceStack. I'm using version 4.5.6 of serviceStack with servicestack-client#^0.0.17. I tried newing up a fresh copy of the dto (PositionFileInfo) and copying over all the values from the parent view just to be sure there wasn't some javascript type conversion weirdness happening that I'm not aware of, but even with a fresh dto the webservice still receives a null request.

Switching from 'client.get(...)' to 'client.post(...)' fixed the problem. Apparently trying to serialize the object over in the URL was not a good plan.

Related

SvelteKit Maintenance Mode

Is there a good way to do display a maintenance page when visiting any route of my SvelteKit website?
My app is hosted on Vercel, for those who want to know.
What I've tried so far:
Set an environment variable called MAINTENANCE_MODE with a value 1 in Vercel.
For development purposes I've set this in my .env file to VITE_MAINTENANCE_MODE and called with import.meta.env.VITE_MAINTENANCE_MODE.
Then inside +layout.server.js I have the following code to redirect to /maintenance route
import { redirect } from "#sveltejs/kit";
export async function load({ url }) {
const { pathname } = url;
// Replace import.meta.env.VITE_MAINTENANCE_MODE with process.env.MAINTENANCE_MODE in Production
if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
if (pathname == "/maintenance") return;
throw redirect(307, "/maintenance");
  } else {
if (pathname == "/maintenance") {
throw redirect(307, "/");
    };
  };
};
What I've also tried is just throwing an error in +layout.server.js with the following:
import { error } from "#sveltejs/kit";
export async function load() {
if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
throw error(503, "Scheduled for maintenance");
  };
};
However this just uses SvelteKit's static fallback error page and not +error.svelte. I've tried creating src/error.html in the hope to create a custom error page for +layout.svelte but couldn't get it to work.
I would like to use a custom page to display "Down for maintenance", but I don't want to create an endpoint for every route in my app to check if the MAINTENANCE_MODE is set to 1.
Any help is appreciated
You could use a handle server hook, e.g. src/hooks.server.ts:
import { env } from '$env/dynamic/private';
import type { Handle } from '#sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
if (env.MAINTENANCE_MODE == '1' && event.routeId != '/maintenance')
return new Response(undefined, { status: 302, headers: { location: '/maintenance' } });
// <other logic>
// Default response
return await resolve(event);
}
And on the maintenance page you can prevent all further navigation:
import { beforeNavigate } from '$app/navigation';
beforeNavigate(async ({ cancel }) => {
cancel();
});
(Possibly add some periodic checks via fetch calls to navigate elsewhere once the site is back online.)
You can also use +layout.ts to hook up for the maintenance mode. You can even make this conditional for some parts of the site (have frontpage still up and running).
Here is the trick we use:
import type { LayoutLoad } from './$types';
import { chainsUnderMaintenance } from '$lib/config';
import { error } from '#sveltejs/kit';
export const load: LayoutLoad = ({ params }) => {
// Check chain maintenance status; if under maintenance, trigger error (see +error.svelte)
const chainName = chainsUnderMaintenance[<string>params.chain];
if (chainName) {
throw error(503, `Chain under maintenance: ${chainName}`);
}
};

How can I use main.dart variable in my JS file?

I'm trying to create a calling app using flutter and I've created the backend using a node.js. This is how my main.dart file in flutter looks like:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_dialpad/flutter_dialpad.dart';
import 'dart:js';
import 'package:js/js.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child:
DialPad(
enableDtmf: true,
outputMask: "(000) 000-0000",
backspaceButtonIconColor: Colors.red,
makeCall: (number){
print(number);
}
)
),
),
);
}
}
I want to use this "number" variable in my app.js file which looks like this:
const accountSid = '***';
const authToken = '***';
const client = require('twilio')(accountSid, authToken);
client.calls.create({
url: 'http://demo.twilio.com/docs/voice.xml',
to: '+10000000',
from: '+1000000',
}, function(err, call){
if (err) {
console.log(err);
} else {
console.log(call.sid);
}
})
I want to be able to use the "number" variable from my main.dart file in the "to" field in my app.js file. Please help me out...
What you need is a way to pass data between applications, and the easiest way for that would be through a REST API
You can use the HTTP module in NodeJS or a third-party package like Express and set up a POST Route to your NodeJS Server, where the number is sent as data.
Once the data is received on your server, you can call your Twilio function, and send a response back.
On Flutter, you can use the http package to make the API call.

Why do I get value TRUE, when the requested photo does not exists in the API and I get http error message?

I am new at learning Angular and Typescript, so I have a bit of trouble. I am working on an app that displays list of photos, allows us to create, edit and delete already existing photos. When I want to open the details page for a photo that doesn't exist, besides that I have a route activator that redirects to 404 not found page when the request is not valid, the page is still being loaded without any data. Here are the error messages I get
"Failed to load resource: the server responded with a status of 404 ()"
and
"core.js:4197 ERROR HttpErrorResponseerror: {}headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}message: "Http failure response for https://jsonplaceholder.typicode.com/photos/5453453: 404 OK"name: "HttpErrorResponse"ok: falsestatus: 404statusText: "OK"url: "https://jsonplaceholder.typicode.com/photos/5453453"proto: HttpResponseBase
defaultErrorLogger # core.js:4197 ".
Here is my route-activator :
import { CanActivate, ActivatedRouteSnapshot, Router } from '#angular/router'
import { Injectable } from '#angular/core'
import { PostsService } from './posts.service'
#Injectable()
export class PostRouteActivator implements CanActivate{
constructor(private postService: PostsService, private router: Router ){
}
canActivate(route:ActivatedRouteSnapshot){
const postExists = !!this.postService.getPost(+route.params['id']);
console.log(postExists)
if (!postExists){
this.router.navigate(['/404']);
}
return postExists
}
}
Here is my getPost function from the service:
getPost(id: number){
return this.http.get<Post>(this.apiUrl + "/" + id);
}
The code for the route:
{ path: 'posts/edit/:id', component: EditPostComponent, canDeactivate: ['canDeactivateCreateEvent'], canActivate: [PostRouteActivator] },
When I print the value of const postExists = !!this.postService.getPost(+route.params['id']); in the console, besides the requested photo/post does not exist, the value I get is TRUE.
Can somebody please help me?
I feel if you handle the error properly then this problem will get easily. So in your PostRoutActivator
Instead of just
#Injectable()
export class PostRouteActivator implements CanActivate{
constructor(private postService: PostsService, private router: Router ){
}
canActivate(route:ActivatedRouteSnapshot){
const postExists = !!this.postService.getPost(+route.params['id']);
console.log(postExists)
if (!postExists){
this.router.navigate(['/404']);
}
return postExists
}
}
If you can
#Injectable()
export class PostRouteActivator implements CanActivate{
constructor(private postService: PostsService, private router: Router ){
}
canActivate(route:ActivatedRouteSnapshot){
const postExists = this.postService.getPost(+route.params['id'])
.pipe(
catchError((err)=>{ // make sure you import this operator
if(err.statusCode == 404) // not sure which property would be just console.log the err and you will know.
{
return false;
} else {
throw err;
}
})
).subscribe((postExists) => {
console.log(postExists)
if (!postExists){
this.router.navigate(['/404']);
}
return postExists
}
});
}

Emitting global events from websocket listener

I want to contribute to a project - it's written in Vue, and I am a beginner in Vue.
I have two components - Setup and MainApp
Both will need to update some state based on different messages from the websocket. Some websocket messages will affect the former, some the latter.
Vue doesn't know services, so I thought I'd just create a custom component, with empty <template>. instantiate the websocket there and then issue an this.emit() every time a new message occurs in the listener.
Both other components would listen to the emits and would be able to react.
Unfortunately, I can't get the websocket component to work.
main.js:
import Ws from './WsService.vue';
//other imports
const routes = [
//routes
]
const router = new VueRouter({
routes // short for `routes: routes`
})
const app = new Vue({
router
}).$mount('#app')
//I thought this to be the way to instantiate my webSocket service:
const WsService = new Vue({
el: '#WsService',
components: { Ws }
});
index.html
<body>
<div id="app">
<div id="WsService"></div>
<router-link to="/setup">Setup</router-link>
<router-link to="/main-app">Main App</router-link>
<router-view></router-view>
</div>
<script src="/dist/demo-app.js"></script>
</body>
the websocket "service":
<template>
</template>
<script>
const PORT_LOCAL = 9988;
var ws = new WebSocket("ws://localhost:" + PORT_LOCAL);
ws.onopen = function() {
ws.send('{"jsonrpc":"2.0","id":"reg","method":"reg","params":null}');
};
ws.onerror = function(e) {
console.log("error in WebSocket connection!");
console.log(e);
};
export default {
data() {
return {
}
},
created() {
var self = this;
ws.onmessage = function(m) {
var msg = JSON.parse(m.data);
switch(msg.id) {
// result for address request
case "reg":
self.$emit("reg_received", msg.result);
break;
case "send":
self.$emit("send_received", msg.result);
break;
case "subscribe":
self.$emit("subscribe_received", msg.result);
break;
default:
console.log(msg);
break;
}
}
},
methods: {
},
send(id, method, params) {
ws.send('{"jsonrpc":"2.0","id":"' + id + '","method":"' + method + '","params":null}');
}
}
}
</script>
Send for example from main app (this seems to work):
import WsSvc from './WsService.vue';
export default {
data() {
//
},
subscribe() {
let jsonrpc = "the jsonrpc string";
WsSvc.send(jsonrpc);
}
}
Listening to emit:
export default {
data() {
//
},
created() {
this.$on("reg_received", function(result){
//do smth with the result
});
}
}
Wit this configuration, the created hook actually never gets called - and thus I'll never hit the onmessage listener. The reason to have a custom component I thought was that I would have access to the emit function.
It feels I am making it more complicated than it should be but I haven't managed yet to get it right. The solution doesn't need to follow this approach.
There's no need for a socket specific component in this case. What I have done in the past on a couple projects is implement an API or store object that handles the socket messages and then import that API or store into the components that need it. Also in a similar answer, I show how to integrate a WebSocket with Vuex.
Here is an example that combines the concept of using Vue as an event emitter with a web socket that can be imported into any component. The component can subscribe and listen to the messages it wants to listen to. Wrapping the socket in this way abstracts the raw socket interface away and allows users to work with $on/$off subscriptions in a more typically Vue fashion.
Socket.js
import Vue from "vue"
const socket = new WebSocket("wss://echo.websocket.org")
const emitter = new Vue({
methods:{
send(message){
if (1 === socket.readyState)
socket.send(message)
}
}
})
socket.onmessage = function(msg){
emitter.$emit("message", msg.data)
}
socket.onerror = function(err){
emitter.$emit("error", err)
}
export default emitter
Here is an example of that code being used in a component.
App.vue
<template>
<ul>
<li v-for="message in messages">
{{message}}
</li>
</ul>
</template>
<script>
import Socket from "./socket"
export default {
name: 'app',
data(){
return {
messages: []
}
},
methods:{
handleMessage(msg){
this.messages.push(msg)
}
},
created(){
Socket.$on("message", this.handleMessage)
},
beforeDestroy(){
Socket.$off("message", this.handleMessage)
}
}
</script>
And here is a working example.
Hey this should work for you better and easy
This my example with .vue file
yourVueFile.Vue
<template>
// key in your template here
</template>
<script>
export default {
//use the created() option to execute after vue instance is created
created() {
let ws = new WebSocket("yourUrl");
ws.onopen = e => {
ws.send(
JSON.stringify({ your json code })
);
ws.onmessage = e => {
let data = JSON.parse(e.data);
// the this.$data get your data() options in your vue instance
this.$data.dom = data;
};
};
},
data() {
return {
dom: core
};
},
methods: {
}
};
</script>

Why aren't any of collections being defined after publishing them?

I keep on getting these error messages in my browser console:
Exception in template helper: ReferenceError: "CollectionNames" is not defined
The "CollectionNames" being all the collections I have in my app. I have researched but cant find a suitable solution.
My environment: I am running meteor 1.2
The task.js file is where I define each collection. Below is the code in task.js
/myMeteorApp
--/imports/api/tasks.js
import { Mongo } from "meteor/mongo";
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
Images = new FS.Collection("images", {
stores: [new FS.Store.FileSystem("images", {path: "~/uploads"})] });
buyList = new Mongo.Collection("BuyList");
WhoAreWe = new Mongo.Collection("whoDb");
merchantReviews = new Mongo.Collection("merchantReviews");
Messages = new Meteor.Collection("messages", {transform: function (doc)
{ doc.buyListObj = buyList.find({sessionIDz: {$in: [doc.buyList]}}); return doc; }});
The server is where I publish the collections. Below is the code:
/myMeteorApp
--/server/main.js
import buyList from '../imports/api/tasks.js';
import Messages from '../imports/api/tasks.js';
import Images from '../imports/api/tasks.js';
import WhoAreWe from '../imports/api/tasks.js';
import merchantReviews from '../imports/api/tasks.js';
Meteor.startup(() => {
// code to run on server at startup
Meteor.publish('buyList', function(){
return buyList.find();
});
Meteor.publish('Messages', function(){
return Messages.find();
});
Meteor.publish('Images', function(){
return Messages.find();
});
Meteor.publish('WhoAreWe', function(){
return WhoAreWe.find();
});
Meteor.publish('merchantReviews', function(){
return merchantReviews.find();
});
});
And the client is where I subscribe for the collections. Find below the code:
/myMeteorApp
--/client/main.js
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
Meteor.subscribe('Messages');
Meteor.subscribe('WhoAreWe');
Meteor.subscribe('Images');
Meteor.subscribe('buyList');
Where am I going wrong. I've been at this for many days now... Kindly help!
The collections must be defined on both the client and the server! Just import your collection names on the client side as well as the server:
import { buyList, Messages, Images, WhoAreWe, merchantReviews } from '../imports/api/tasks.js';
You still have to subscribe to the various publications of course.
It is a naming problem, when you publish the collection, you should refer to the collection name (messages), not the meteor variable (Messages)
Meteor.publish('messages', function(){...

Categories

Resources