Consuming WCF from other projects - wcf

I'm very new to silverlight and WCF Ria services. I have background experience in WPF and WinForms.
Right now I'm developing a silverlight application that consists basically on a web page fetching data from a remote server.
I've read tons of forums and articles that explain how to use and consume web services and WCF. I've followed the msdn walkthrough on how to create a simple app that gets data from a DB and it worked great.
The problem is that I don't want any WCF related code or resource in my UI controls.
Right now I'm using using the layered programming architecture:
UI --> BLL --> DAL
Each of these elements is a single project in the same solution. My DAL project is the web service (WCF Ria) that comunicates with the server.
I have a simple class (User Service) and method (GetUsers) in my DAL project with the following code:
LoadOperation<u_WEBUSERS> loadOp = this.userContext.Load(this.userContext.GetU_WEBUSERSQuery());
loadOp.Completed += (sender, args) =>
{
users = new List<UserObj>();
foreach (var v in loadOp.Entities)
{
u_WEBUSERS uweb = v as u_WEBUSERS;
UserObj u = new UserObj();
u.Nome = uweb.nome;
u.Morada = uweb.morada;
users.Add(u);
}
};
return users;
The thing is that my users object returns null. If I breakpoint I see that first is ending the method and only after is calling the completed event.
Is there any way make my GetUsers() to return the data base information?
Maybe the layered achitecture that I'm using isn't the one suited for what I want...
Thanks

You can use simple Action or Action<T> delegate:
public void LoadUsers(Action<IEnumerable<UserObj>> callBack)
{
LoadOperation<u_WEBUSERS> loadOp = this.userContext.Load(this.userContext.GetU_WEBUSERSQuery());
loadOp.Completed += (sender, args) =>
{
users = new List<UserObj>();
foreach (var v in loadOp.Entities)
{
u_WEBUSERS uweb = v as u_WEBUSERS;
UserObj u = new UserObj();
u.Nome = uweb.nome;
u.Morada = uweb.morada;
users.Add(u);
}
if(callBack != null)
callBack(users);
};
}

You're mixing synchronous and asynchronous code together. You're setting up the completed event but the call doesn't return until it completes when you don't specify a handler. See the example here. So your code would be:
LoadOperation<u_WEBUSERS> loadOp = this.userContext.Load(this.userContext.GetU_WEBUSERSQuery());
users = new List<UserObj>();
foreach (var v in loadOp.Entities)
{
u_WEBUSERS uweb = v as u_WEBUSERS;
UserObj u = new UserObj();
u.Nome = uweb.nome;
u.Morada = uweb.morada;
users.Add(u);
}
return users;

Related

ABP: Rebuilding Localization Sources from Custom Provider

I am using ABP v4.9.0 (.NET CORE 2.2) with angular client
I built some custom localization providers. These providers get translation dictionaries from an external API.
I add localization sources on startup with these providers.
var customProvider = new CustomLocalizationProvider(...);
var localizationSource = new DictionaryBasedLocalizationSource("SOURCENAME", customProvider );
config.Localization.Sources.Add(localizationSource );
On startup, the providers InitializeDictionaries() is called and localization dictionaries are built.
So far, so good, working as intended.
Now i'd like to manually Reload these translations on demand, but I can't make this working.
Here is what I tried.
Here I trigger the re-synchronize of the language ressources:
foreach (var localizationSource in _localizationConfiguration.Sources)
{
try
{
localizationSource.Initialize(_localizationConfiguration, _iocResolver);
}
catch (Exception e)
{
Logger.Warn($"Could not get Localization Data for source '{localizationSource.Name}'", e);
}
}
In the custom provider, I first clear the Dictionaries
public class CustomLocalizationProvider : LocalizationDictionaryProviderBase
{
protected int IterationNo = 0;
protected override void InitializeDictionaries()
{
Dictionaries.Clear();
IterationNo += 1;
var deDict = new LocalizationDictionary(new CultureInfo("de-DE"));
deDict["HelloWorld"] = $"Hallo Welt Nummer {IterationNo}";
Dictionaries.Add("de-DE", deDict);
var enDict = new LocalizationDictionary(new CultureInfo("en"));
enDict["HelloWorld"] = $"Hello World number {IterationNo}";
Dictionaries.Add("en", enDict);
}
}
The provider is executed again as expected.
But when I eventually use the localization clientside (angular), I still get the original translations.
What am I missing?
Thanks for the help.
In the meanwhile I had to go for another approach.
I am now using a XmlEmbeddedFileLocalizationDictionaryProvider wrapped by a MultiTenantLocalizationDictionaryProvider.
This way, I am using db-localizations with xml-sources as fallback
Then I manually load the ressources from my API in some appservice. These localizations are then updated in the database by using LanguageTextManager.UpdateStringAsync().

Genesys Platform : Get Call Details From Sip Server

I want to get Call Details from Genesys Platform SIP Server.
And Genesys Platform has Platform SDK for .NET .
Anybod has a SIMPLE sample code which shows how to get call details using Platform SDK for .NET [ C# ] from SIP Server?
Extra Notes:
Call Details : especially i wanted to get AgentId for a given call
and
From Sip Server : I am not sure if Sip Server is the best candiate to
take call details. So open to other suggestions/ alternatives
You can build a class that monitor DN actions. Also you watch specific DN or all DN depending what you had to done. If its all about the call, this is the best way to this.
Firstly, you must define a TServerProtocol, then you must connect via host,port and client info.
var endpoint = new Endpoint(host, port, config);
//Endpoint backupEndpoint = new Endpoint("", 0, config);
protocol = new TServerProtocol(endpoint)
{
ClientName = clientName
};
//Sync. way;
protocol.Open();
//Async way;
protocol.BeginOpen();
I always use async way to do this. I got my reason thou :) You can detect when connection open with event that provided by SDK.
protocol.Opened += new EventHandler(OnProtocolOpened);
protocol.Closed += new EventHandler(OnProtocolClosed);
protocol.Received += new EventHandler(OnMessageReceived);
protocol.Error += new EventHandler(OnProtocolError);
Here there is OnMessageReceived event. This event where the magic happens. You can track all of your call events and DN actions. If you go genesys support site. You'll gonna find a SDK reference manual. On that manual quiet easy to understand there lot of information about references and usage.
So in your case, you want agentid for a call. So you need EventEstablished to do this. You can use this in your recieve event;
var message = ((MessageEventArgs)e).Message;
// your event-handling code goes here
switch (message.Id)
{
case EventEstablished.MessageId:
var eventEstablished = message as EventEstablished;
var AgentID = eventEstablished.AgentID;
break;
}
You can lot of this with this usage. Like dialing, holding on a call inbound or outbound even you can detect internal calls and reporting that genesys platform don't.
I hope this is clear enough.
If you have access to routing strategy and you can edit it. You can add some code to strategy to send the details you need to some web server (for example) or to DB. We do such kind of stuff in our strategy. After successful routing block as a post routing strategy sends values of RTargetPlaceSelected and RTargetAgentSelected.
Try this:
>
Genesyslab.Platform.Contacts.Protocols.ContactServer.Requests.JirayuGetInteractionContent
JirayuGetInteractionContent =
Genesyslab.Platform.Contacts.Protocols.ContactServer.Requests.JirayuGetInteractionContent.Create();
JirayuGetInteractionContent.InteractionId = "004N4aEB63TK000P";
Genesyslab.Platform.Commons.Protocols.IMessage respondingEventY =
contactserverProtocol.Request(JirayuGetInteractionContent);
Genesyslab.Platform.Commons.Collections.KeyValueCollection keyValueCollection =
((Genesyslab.Platform.Contacts.Protocols.ContactServer.Events.EventGetInteractionContent)respondingEventY).InteractionAttributes.AllAttributes;
We are getting AgentID and Place as follows,
Step-1:
Create a Custome Command Class and Add Chain of command In ExtensionSampleModule class as follows,
class LogOnCommand : IElementOfCommand
{
readonly IObjectContainer container;
ILogger log;
ICommandManager commandManager;
public bool Execute(IDictionary<string, object> parameters, IProgressUpdater progress)
{
if (Application.Current.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess())
{
object result = Application.Current.Dispatcher.Invoke(DispatcherPriority.Send, new ExecuteDelegate(Execute), parameters, progress);
return (bool)result;
}
else
{
// Get the parameter
IAgent agent = parameters["EnterpriseAgent"] as IAgent;
IIdentity workMode = parameters["WorkMode"] as IIdentity;
IAgent agentManager = container.Resolve<IAgent>();
Genesyslab.Desktop.Modules.Core.Model.Agents.IPlace place = agentManager.Place;
if (place != null)
{
string Place = place.PlaceName;
}
else
log.Debug("Place object is null");
CfgPerson person = agentManager.ConfPerson;
if (person != null)
{
string AgentID = person.UserName;
log.DebugFormat("Place: {0} ", AgentID);
}
else
log.Debug("AgentID object is null");
}
}
}
// In ExtensionSampleModule
readonly ICommandManager commandManager;
commandManager.InsertCommandToChainOfCommandAfter("MediaVoiceLogOn", "LogOn", new
List<CommandActivator>() { new CommandActivator()
{ CommandType = typeof(LogOnCommand), Name = "OnEventLogOn" } });
enter code here
IInteractionVoice interaction = (IInteractionVoice)e.Value;
switch (interaction.EntrepriseLastInteractionEvent.Id)
{
case EventEstablished.MessageId:
var eventEstablished = interaction.EntrepriseLastInteractionEvent as EventEstablished;
var genesysCallUuid = eventEstablished.CallUuid;
var genesysAgentid = eventEstablished.AgentID;
.
.
.
.
break;
}

I need help testing NServiceBus.Send(command).Register(delegate) in a MVC 4 Web API service call

I'm implementing a call to NServiceBus.Send() inside a MVC 4 Web API Service call. I'm doing this in .Net 4, so I don't have access to C# 5 features (async, etc.).
I'm very new to Moq, so I'd appreciate some advice creating the correct way to Setup Moq for this. I did look at [Mocking a delegate wrapper using Moq][1] and [Testing Bus Send in an application using NServiceBus][2] but my understanding of Moq is still to primitive to adapt for my testing needs, especially with the Tasks involved to deal with the asynchronous calls:
public Task<HttpResponseMessage> Post(Command command)
{
var commandCompletion = new TaskCompletionSource<HttpResponseMessage>();
var commandCompletionTask = commandCompletion.Task;
Bus.Send(command).Register<CommandResult>(status =>
{
var response = new HttpResponseMessage { StatusCode = HttpStatusCode(status) };
commandCompletion.SetResult(response);
});
return commandCompletionTask;
}
I run into trouble because I don't know how to reference the commandCompletionTask within the mockedBus... My failed attempt looks like this:
_commandController = new CommandController(MockBus.Object);
MockBus.Setup(b => b.Send(It.IsAny<ICommand>()).Register<CommandResult>((Action<CommandResult> s) =>
{
var response = new HttpResponseMessage { StatusCode = HttpStatusCode(s) };
commandCompletion.SetResult(response);
}));
Writing this allowed my brain to come up with a couple of ideas...
To Moq TaskCompletionSource, but that doesn't have an interface, so can't be Moq'd apparently.
To use a real TaskCompletionTask, (which allows me to test for the Task returned from CommandController.Post()). Sadly this didn't work any better, as I get an error from LINQ as it tries to process the delegate.
Ideas/suggestions?

Silverlight RIA query with client-side filtering

I have the following query that returns empty (enumeration yielded no results):
CurrentStudent = _ctx.Students.SingleOrDefault();
var qry = _ctx.GetStudentsWithAdultContactsQuery();
_ctx.Load(qry.Where(s => s.StudentID == studentId));
dataForm1.CurrentItem = CurrentStudent;
BeginEdit();
Instead, I have to do the following, as if I were working with a regular SL WCF Service:
var qry = _ctx.GetStudentByIDQuery(studentId);
var load = _ctx.Load(qry);
load.Completed += (s, e) =>
{
CurrentStudent = _ctx.Students.FirstOrDefault();
dataForm1.CurrentItem = CurrentStudent;
BeginEdit();
};
Why does the first method not work? The server-side query does the same filtering by ID as the first, so it's not the query itself. None of the examples of using RIA that I've seen use the Completed event handler; RIA is supposed to handle the asynchronous loading behind the scenes. What gives?
EDIT
I wanted to refocus the question a bit. Here's another query that I have that works just as you would expect:
var query = ctx.GetStudentsWithAdultContactsQuery();
studentDataGrid.ItemsSource = ctx.Students;
ctx.Load(query);
I am not explicitly handling the Completed callback here, and that's how I see RIA used in examples on the web, including here. So, the obvious differences between this query and the one that doesn't work is (a) the filtering and (b) the databinding target. But why should either make a difference?
I think I've worked out an answer:
The two situations -- binding a grid and binding a dataform -- are different because in the former scenario I am binding to an EntitySet (Students) while in the case of the dataform I am binding to an individual entity (Student). Well, duh! But so what?
So, an EntitySet implements INotifyCollectionChanged, which raises a notification event when entities are added to the set (as when the query returns with the results), causing the grid to update. The dataform CurrentItem, on the other hand, is not binding to an EntitySet, so it's not listening to changes in the Students collection and doesn't know when CurrentStudent is no longer null. Hence, I have to wait for the load to complete, or I can do something that the grid presumably does, and listen to the Students collection, which works to the same effect:
var qry = _ctx.GetStudentsWithAdultContactsQuery().Where(s => s.StudentID == studentId);
_ctx.Load(qry);
_ctx.Students.EntityAdded += new EventHandler<EntityCollectionChangedEventArgs<Student>>(Students_EntityAdded);
//...
void Students_EntityAdded(object sender, EntityCollectionChangedEventArgs<Student> e)
{
dataForm1.CurrentItem = e.Entity;
}
Or, more succinctly:
var qry = _ctx.GetStudentsWithAdultContactsQuery();
_ctx.Load(qry.Where(s => s.StudentID == studentId));
_ctx.Students.EntityAdded += (s, e) => {
dataForm1.CurrentItem = e.Entity;
};
I'm marking the question as answered, but please feel welcome to post your explanation if it differs from mine; I will happily vote it up if it offers new insight.

Creating an SPListItem in a WCF service deployed to SharePoint

i have the following method in a WCF service, that has been deployed to SharePoint using Shail Malik's guide:
[OperationContract]
public string AddItem(string itemTitle, Guid? idOfListToUse)
{
using (var portal = new SPSite(SPContext.Current.Site.Url, SPContext.Current.Site.SystemAccount.UserToken))
{
using (var web = portal.OpenWeb())
{
Guid listId;
web.AllowUnsafeUpdates = true;
if (idOfListToUse != null && idOfListToUse.Value != new Guid())
{
listId = idOfListToUse.Value;
}
else
{
try
{
listId = new Guid(web.Properties[PropertyBagKeys.TagsList]);
}
catch (Exception ex)
{
throw new MyException("No List Id for the tag list (default list) has been found!", ex);
}
}
var list = web.Lists[listId];
string title = "";
SPSecurity.RunWithElevatedPrivileges(delegate{
var newItem = list.Items.Add();
newItem["Title"] = itemTitle;
newItem.Update();
title = newItem.Title;
});
web.AllowUnsafeUpdates = false;
return title;
}
}
}
When the method gets called from Javascript (using Rick Strahl's excellent ServiceProxy.js) it fails and it does so on newItem.Update() because of ValidateFormDigest().
Here's the kicker though, when I step through the code it works! No exceptions at all!
Ok, found the answer (there's 2 even :-D)
First, the dirty one:
Set FormDigestValidatedProperty in the context:
HttpContext.Current.Items["FormDigestValidated"] = true;
Second, the slightly less dirty version (basically leaving the way open for XSS attacks, but this is an intranet anyway)
The answer
I don't think you can access 'list' as it was created outside the elevated code block.
http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=8
I'm guessing when you are stepping though the entire process is in admin mode so all are elevated.
Colin, it's a really bad idea to try to access HttpContext (likewise SPContext) inside a WCF service. See here: MSDN: WCF Services and ASP.NET
From the article:
HttpContext: Current is always null
when accessed from within a WCF
service.
It's likely this is the cause of your problem.
EDIT: I notice that you're trying to use SPContext to get the url of the site collection. I didn't find a good solution to this either so I just send the url of the target site collection as a parameter to the service call. Not the most optimal solution but I couldn't think of a better way. Also, if you need to check authentication/identities, etc use ServiceSecurityContext.Current.