I am sending userid from javascript while i am making request to signalr as follows:
var userId = "1";
var connection = $.hubConnection("/signalr", { useDefaultPath: false });
var notificationsHubProxy = connection.createHubProxy('NotificationsHub');
connection.qs = "userId=" + userId;
notificationsHubProxy.on('notify', function (notifications) {
notifyAll(notifications);
});
connection.start()
.done(function() {
notificationsHubProxy.invoke('getNotifications', "1,2,3");
})
.fail(function(reason) {
alert('signalr error');
});
Here is the class for implementing IUserIdProvider that retrieves querystring and returns as userId, i debugged and this class and GetUserId method was not invoked by the framework.
public class RealTimeNotificationsUserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
return request.QueryString["userId"];
}
}
Here is my startup class for hooking up IUserId provider with signalR configuration:
var userIdProvider = new RealTimeNotificationsUserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => userIdProvider);
app.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
Resolver = dependencyResolver,
EnableJavaScriptProxies = false
};
map.RunSignalR(hubConfiguration);
});
Now, when i try to send notification to a particular User by accessing Clients.User(userId) its not working:
var userId = "1";
Clients.User(userId).notify("test");
what am i missing? Please help.
What you have looks like it should work. The only thing that looks suspicious is that you are registering your IUserIdProvider with GlobalHost.DependencyResolver, but then you have Resolver = dependencyResolver in your HubConfiguration.
There is no other reference to dependencyResolver anywhere else in your question. If you were to leave out Resolver = dependencyResolver, SignalR would use GlobalHost.DependencyResolver by default.
hier is what I did to solve this problem, form me request.QueryString["userId"] did not return user id that is why it did not work, I change your code like below and it does work I tested t on my project:
using using System.Web;
public class RealTimeNotificationsUserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
return HttpContext.Current.User.Identity.GetUserId()
}
}
remove var userIdProvider = new RealTimeNotificationsUserIdProvider() and write it like below:
ConfigureAuth(app);
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => new RealTimeNotificationsUserIdProvider());
app.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
EnableJavaScriptProxies = false
};
map.RunSignalR(hubConfiguration);
});
Related
I am developping a JHipster blueprint and I need to use EJS to template the files I want to generate. Since this is my first time using EJS, all I am trying to do for now is use an answer from one of the generated question and create a java interface with its name.
This is the template I got:
public interface <%= databaseURL %> {
}
prompts.js:
function askForDatabaseURL(meta) {
const applicationType = this.applicationType;
const prompts = [
{
type: 'string',
name: 'databaseURL',
message:
'Quel est l\'URL de votre base de données ?',
default: 'URL'
}
];
if (meta) return PROMPTS;
const done = this.async();
this.prompt(prompts).then(prompt => {
this.log(this.databaseURL);
this.databaseURL = prompt.databaseURL;
this.log(this.databaseURL);
done();
});
}
module.exports = {
askForDatabaseURL
};
index.js:
const chalk = require('chalk');
const AppGenerator = require('generator-jhipster/generators/app');
const prompts = require('./prompts');
module.exports = class extends AppGenerator {
constructor(args, opts) {
super(args, { fromBlueprint: true, ...opts }); // fromBlueprint variable is important
this.databaseURL = "Hello";
}
get initializing() {
return super._initializing();
}
_prompting() {
return {
askForDatabaseURL: prompts.askForDatabaseURL
}
}
get prompting() {
const defaultPhaseFromJHipster = super._prompting();
const myPrompting = this._prompting();
return Object.assign(defaultPhaseFromJHipster, myPrompting);
}
get configuring() {
return super._configuring();
}
get default() {
return super._default();
}
_writing() {
this.fs.copyTpl(
this.templatePath(`src/main/java/package/repository/JOOQRepository.java.ejs`),
this.destinationPath(`${this.databaseURL}.java`),
{ databaseURL : this.databaseURL}
)
}
get writing() {
const defaultPhaseFromJHipster = super._writing();
const myWriting = this._writing()
return Object.assign(defaultPhaseFromJHipster, myWriting);
}
get install() {
return super._install();
}
get end() {
return super._end();
}
};
The problem is, after the prompting phase, this.databaseURL always has a value of "Hello" which is the default value in the constructor, meaning the file generated is always Hello.java.
I tried to add this.log(this.databaseURL); before and after this.databaseURL = prompt.databaseURL so I'd get an idea if this line does what it's supposed to and it does:
I am fairly new to JavaScript so I might have missed something very basic, but I don't understand why this.databaseURL returns "Hello" after assigning it the user's answer to it.
Any help is welcomed!
I have a function that when the component is loaded, it returns specific data of a certain parameter (ex: /app/items) and displays them in an information balloon, but if I access a child route (ex: /app/items/ create) or (ex: /app/items/1/view) I need to do a validation to see if there is informational data in this route to display, but if not, I need to display the information from the previous parameter (ex: /app/items) . I managed to create this function below that fulfills this, but with a request inside another, which I believe is not the most appropriate. So I'm trying to refactor so that only one request is made validating these parameters. It should also be considered that if the route has numbers, it needs to be filtered and returned an array with just the strings before doing the join('/'), as you can see there in the constructor. I'm new to the area, so I'm trying to find some background to refactor this function.
public information: InformationList | any
public isLoading:boolean = true
error: any;
showError: boolean = false
public currentPageUrl = null;
public output = null
other: any;
constructor(
public screenInfoService: ScreenInfoService,
public loaderService: LoaderService,
public router: Router
) {
this.currentPageUrl = this.router.url.split("/").filter((item: any) => {
return isNaN(item)
})
}
load() {
this.output = this.currentPageUrl.join("/");
let params = new HttpParams();
params = params.set('orderBy', 'id');
params = params.set('search', `path:${this.output}`);
params = params.set('searchFields', `path:ilike`);
params = params.set('searchJoin', 'and');
this.screenInfoService.getAll(params).subscribe(
success => {
if (success.length === 0) {
let output2 = null
output2 = this.currentPageUrl.slice(0,2).join("/");
params = params.set('orderBy', 'id');
params = params.set('search', `path:${output2}`);
params = params.set('searchFields', `path:ilike`);
params = params.set('searchJoin', 'and');
this.screenInfoService.getAll(params).subscribe(
success => {
this.information = success
}, error => {
this.error = 'MSG.T224';
this.showError = true;
}
)
} else {
this.information = success
}
}, error => {
this.error = 'MSG.T224';
this.showError = true;
});
}
ngOnInit(): void {
this.load()
}
i want to share data between components, so im implemented a Service which has an EventEmitter.
My Service looks like this:
#Injectable()
export class LanguageService {
constructor() {
this.languageEventEmitter = new EventEmitter();
this.languages = [];
this.setLanguages();
}
setLanguages() {
var self = this;
axios.get('/api/' + api.version + '/' + api.language)
.then(function (response) {
_.each(response.data, function (language) {
language.selected = false;
self.languages.push(language);
});
self.languageEventEmitter.emit(self.languages);
})
.catch(function (response) {
});
}
getLanguages() {
return this.languages;
}
toggleSelection(language) {
var self = this;
language.selected = !language.selected;
self.languages.push(language);
self.languageEventEmitter.emit(self.languages);
}
}
I have to components, which are subscribing to the service like this:
self.languageService.languageEventEmitter.subscribe((newLanguages) => {
_.each(newLanguages, function (language) {
self.updateLanguages(language);
});
});
When both components are loaded, the language arrays get filled as i wish.
This is the first component:
export class LanguageComponent {
static get parameters() {
return [[LanguageService]];
}
constructor(languageService) {
var self = this;
this.languageService = languageService;
this.languages = [];
this.setLanguages();
}
setLanguages() {
var self = this;
self.languageService.languageEventEmitter.subscribe((newLanguages) => {
_.each(newLanguages, function (language) {
self.updateLanguages(language);
})
});
}
updateLanguages(newLanguage) {
var self = this;
if (!newLanguage) {
return;
}
var match = _.find(self.languages, function (language) {
return newLanguage._id === language._id;
});
if (!match) {
self.languages.push(newLanguage);
}
else {
_.forOwn(newLanguage, function (value, key) {
match[key] = value;
})
}
toggleLanguageSelection(language) {
var self = this;
self.languageService.toggleSelection(language)
}
}
When LanguageComponent executes the function toggleLanguageSelection() which triggered by a click event, the other component, which subscribes like this:
self.languageService.languageEventEmitter.subscribe((newLanguages) => {
_.each(newLanguages, function (language) {
self.updateLanguages(language);
})
});
doesn't get notfiefied of the change. I think this happens because both component get a different instance of my LanguageService, but i'm not sure about that. I also tried to create a singleton, but angular'2 di doesn't work then anymore. What is the reason for this issue and how can i solve this ?
You need to define your shared service when bootstrapping your application:
bootstrap(AppComponent, [ SharedService ]);
and not defining it again within the providers attribute of your components. This way you will have a single instance of the service for the whole application. Components can leverage it to communicate together.
This is because of the "hierarchical injectors" feature of Angular2. For more details, see this question:
What's the best way to inject one service into another in angular 2 (Beta)?
I have the following BreezeController
[BreezeController]
public class BreezeController : ApiController
{
readonly EFContextProvider<MyContext> _ContextProvider = new EFContextProvider<MyContext>();
[HttpGet]
public string Metadata()
{
return _ContextProvider.Metadata();
}
....other controllers exposing model types....
[HttpGet]
public IQueryable<Size> Sizes()
{
return _ContextProvider.Context.Sizes;
}
}
which I access from the client from my DataContext.js with this
var getSizes = function (sizesObservable, modelId) {
var query = entityQuery.from('Sizes').where('ID', '==', modelId)
.orderBy('sortOrder').orderBy('size').orderBy('enteredDate');
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
if (sizesObservable) {
var intialValues = { size: ' Select a Size', sizeID: breeze.core.getUuid(), modelID: modelId };
createNullo(entityNames.size, 'Size', intialValues);
sizesObservable(data.results);
}
log('Retrieved [Sizes] from remote data source', data, false);
}
};
All of this works just fine. I would like to add another route to my controller that has some specialized filtering done on the server.
[HttpGet]
public IQueryable<Size> GetUniqueSizes()
{
return //custom filtering logic here.
}
with the following javascript in my DataContext.js
var getUniqueSizes = function (sizesObservable, modelId) {
var query = entityQuery.from('GetUniqueSizes').where('modelID', '==', modelId).where('Approved', '==', 'True')
.orderBy('sortOrder').orderBy('size').orderBy('enteredDate');
return manager.executeQuery(query)
.then(querySucceeded);
function querySucceeded(data) {
if (sizesObservable) {
var intialValues = { size: ' Select a Size', sizeID: breeze.core.getUuid(), modelID: modelId };
createNullo(entityNames.size, 'Size', intialValues);
sizesObservable(data.results);
}
log('Retrieved [Sizes] from remote data source', data, false);
}
};
but when I do this I get the following error on the client
TypeError: Cannot read property 'toODataFragment' …localhost:63144/scripts/breeze.debug.js:12728:23)
Why is this route not working?
try changing the multiple orderBy statements to a multiple property sort.
.orderBy('sortOrder,size,enteredDate')
likewise, you might have better luck if you combine the where clauses.
I am trying to get metadata back from my "contact" object to breeze so I can map the metadata to a "contactdto" object. On the server I have a Web API function called GetContactsMetadata
[HttpGet]
public IQueryable<Contact> GetContactsMetadata()
{
return _contextProvider.Context.Contacts.Take(1);
}
I'm sure I'll remove the IQueryable and/or list once I get this example running. on the client I have the following
//GetContactsMetadata
var myJsonResultsAdapter = new breeze.JsonResultsAdapter({
name: "GetContactsMetadata",
extractResults: function (json) {
return json.results;
},
visitNode: function (node, parseContext, nodeContext) {
var entityType = normalizeTypeName(node.$type);
var propertyName = nodeContext.propertyName;
var ignore = propertyName && propertyName.substr(0, 1) === "$";
return {
entityType: entityType,
nodeId: node.$id,
nodeRefId: node.$ref,
ignore: ignore
};
}
});
var dataService = new breeze.DataService({
serviceName: 'api/contacts',
jsonResultsAdapter: myJsonResultsAdapter
});
var manager = new breeze.EntityManager({ dataService: dataService });
It keeps erroring in chrome with: "normalizeTypeName is not defined". Am I calling the JsonResultsAdapter correctly?
I should have been clearer in the example.
The normalizeTypeName method is a method you as the dev would write that would take some property on the node and return a Breeze EntityType or a Breeze EntityType name. If you actually know the type name and are only using this adapter for a single type of query you can do something as simple as this:.
visitNode: function (node, parseContext, nodeContext) {
return {
entityType: "Contact" // or "ContactDTO" depending on what you are calling the type on the client.
};
}