I am completely new in Windows Phone development and I am trying to write an app that retrieves the data from a server and displays them to the user. I have several resources on the server, lets say User, Quest and Activity. I use RestSharp lib to retrieve the data from the server.
Example of Get User:
public void Get(String id, LifeHunt.MainPage.UserReady userReady)
{
var client = new RestClient(Deployd.REST_URL);
var request = new RestRequest(resource + "/{id}", Method.GET);
request.AddUrlSegment("id", id);
client.ExecuteAsync<User>(request, response =>
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
userReady(callback.Data);
}
});
}
Once the user is retrieved, I call the userReady method I passed as callback and get the user to MainPage to display it.
Now, I have to repeat the whole process for all CRUD (Insert, Get, GetAll, Update, Delete) functions for all Users, Quest and Activity. That means I will need 15 different callback methods, which I think is not a good software design.
The other way would be just one callback method and check the type of parameter passed in the callback method. However I do not think this is a nice solution as well.
I was thinking about something like creating a generic interface for CRUD, implement it by all the User, Quest and Activity classes:
interface ICRUD<T>
{
void GetAll(GenericCallback callback);
void Get(GenericCallback callback);
void Add(T item, GenericCallback callback);
void Remove(String id, GenericCallback callback);
void Update(T item, GenericCallback callback);
}
However I do not really know how to implement it and even if it is a good way. Could somebody suggest me a good design solution?
Use MVVM, create a ViewModel that would hold all the data you need and bind it to the View. Then create Service class with methods directly returning the data you need (no callbacks). Create a instance of this Service in the ViewModel and call the methods to get and fill the data when needed.
Related
I'm currently writing a custom logging method for my Web API where users can purchase items. This log method will log all the steps the users takes while following a purchase process so support can later track the steps. There are multiple steps like:
Creating a order
Updating a order
Purchasing a item
Receiving status
etc..
This method will return one 'Event' object where all the necessary log information is combined, for example the LogLevel, Message, UserId and more, and write this to a database.
Before i can reach this point, i have to create the very useful log message. The message is based on these two enums (explanation is a bit simplified):
ActionName - At which step in my process is this log event called
ActionOrigin - Is the recorded log event from my front end or backend system...
It is also based on a object where the necessary log values, like order id for example, are provided.
The log class where the log event method is defined is a scoped injected class so i can log events every where critical in my code.
The first thing that came into my mind was creating a switch statement and create the messages based on the correct case. But this would combine 2 switch statements and quickly started to look like a mess.
I did some research and found the strategy pattern. I'm not completely sure if this can help me? Are there any other ideas or examples?
Whenever you are working on an object model and find yourself writing a ton of switch statements, it usually means you've put the class-specific logic in the wrong place. You should put it with the class itself, not the class that consumes it.
To put it another way, your logger should not know how to log each and every type of event. That would be a maintenance nightmare. Instead, it should know how to log a common object (e.g. a string), and each event should itself know how to create that common object, via a common method that the logger knows about. That is the only thing it needs to know.
Here is a simple example. In this case, the logger accepts any type of LoggableEvent and calls its Serialize() method to figure out how it gets added to the common log. The event itself is responsible for knowing how to serialize itself.
abstract class LoggableEventBase
{
public string ActionName { get; }
public string ActionOrigin { get; }
public LoggableEventBase(string actionName, string actionOrigin)
{
ActionName = actionName;
ActionOrigin = actionOrigin;
}
public virtual string Serialize()
{
return string.Format("{0} {1}", ActionName, ActionOrigin);
}
}
class CreateOrderEvent : LoggableEventBase
{
protected readonly List<Item> _items;
protected readonly int _orderId;
public CreateOrderEvent(string origin, int orderID, List<Item> items) : base("CreateOrder", origin)
{
_orderId = orderID;
_items = items;
}
public override string Serialize()
{
return base.Serialize() + string.Format(" {0} {1}", _orderId, string.Join(",", _items.Select(item => item.SKU)));
}
}
Now the actual logging logic is rather simple-- no switch statements or anything else that needs to know what the event is:
class Logger : ILogger
{
public void Log(LoggableEventBase eventToLog)
{
Write(eventToLog.Serialize());
}
protected virtual void Write(string message)
{
//Write the message to a log file
}
}
To add additional event types, you just need to define the new class (and override Serialize()). You never have to go back and modify the Logger class. This is more consistent with the Open-Closed Principle than your existing solution.
This is a design pattern question. You might want to read on different patterns used for the language/framework you are using. It seems like you are trying to avoid writing your logs in line. One way of doing it would be to define the format for your different messages in a constant and use string interpolation (or simple concatenation) to build the message with a log() method.
Example (I'll do my best to write proper C#, please edit any mistakes or inadequacies):
class Logger {
// If you want personalized messages for different actions or origins, define their template constants and create different methods for building them.
public const string ORDER_PROGRESS_MSG_TMPL = "Action:{0}, Origin:{1}, OrderId:{3}";
void log_order_progress(string actionName, sting actionOrigin, string orderId){
Console.WriteLine(
ORDER_PROGRESS_MSG_TMPL, actionName, actionOrigin, orderId
);
}
}
Order
class Order {
...
void create(int orederId){
Logger.log_order_progress(ActionEnum.CREATING, OriginEnum.BACK_END, orderId)
// Do some stuff here to create order
Logger.log_order_progress(ActionEnum.UPDATING, OriginEnum.BACK_END, orderId)
// etc
}
}
This is a way of doing it, you could modularize it more by having templates in their own class. Also you could create (or better: use an existing logging framework) to differentiate level of logging (debug, info, error) as #Sandeep Sharma described.
You can create multiple methods in your Logger class, each for specific scenario.
The methods can be :
info() = for logging some information.
debug() = for debugging.
error() = for logging an error event.
Let's say you want to log an event of purchasing an item , and when user does buy action, you can pass information to the logger.info() method.
If you encounter an error, or a certain action or condition was not fulfilled , you can pass data to the method error() , which will log error in your case.
For messages :
1. Action Name - You can pass the method name or route path that was called by action of an user.
2. Action Origin - Provide details like user name , full path , action type etc.
You can also maintain fields like 'timestamp' and some 'unique-identifier' for better logging of events.
I have a button, that when clicked will/should notify the server. The server will then save a value to the database. If all went well, it should return true, otherwise return false.
I instantiate a hub in my view
var signalRhub = $.connection.hubSignalR;
Start the connection:
$.connection.hub.start().done(function () {
$("#submitBut").click(function () {
signalRhub.server.cardAdded();
});
});
Define the function that will be used by the server to return the boolean value:
signalRhub.client.cardAddedRes = function (isSuccess) {
alert("From server: " + isSuccss);
}
My Hub class:
public class HubSignalR : Hub
{
public bool isSuccess = false; <-- Will be set from controller
public void CardAdded()
{
Clients.Caller.CardAddedRes(isSuccess); <-- Notice the isSuccess
}
}
My problem is that the isSuccess value is coming from my controller, that interacts with the model/database.
So I get the error:
Using a Hub instance not created by the HubPipeline is unsupported.
I tried using: GlobalHost.ConnectionManager.GetHubContext<HubSignalR>()
but I can't make it work.
Here is the relevant code in my controller:
private HubSignalR signalR = new HubSignalR(); <-- Field variable
[HttpPost]
public ActionResult AttachCard(Card model, int MemberID)
{
var hub = GlobalHost.ConnectionManager.GetHubContext<HubSignalR>();
...
//We saved to the database, so we call the client function with bool = true
hub.Clients.All.CardAdded(true); <-- Actually I want to send to one client, NOT ALL
//Something like hub.Clients.Caller.CardAdded();
}
I'm forced to make the isSuccess field in my: HubSignalR class, since I need to return that as the parameter from my controller. But when the button is clicked, this value has not yet been set (I think).
I can see from the debugger, that I do reach: signalRhub.server.cardAdded();
But the server never responds, so I don't reach this function:
signalRhub.client.cardAddedRes = function (isSuccess) {
alert("From server: " + isSuccss);
}
I don't really get to call the CardAdded() method from my controller, cus of the GlobalHost.ConnectionManager.GetHubContext. But you can see
If you got a nicer solution than what I'm trying to do, please tell. I'm total new with SignalR and fairly new with ASP.net MVC
Hope I got the problem right: you want to set isSuccess in controller and send it to specific client, but don't reach specific client from outside the hub?
As to "how":
You should find a way to identify your client, i.e. implement some kind of authentication. More on this here: Authentication in .net core When clients connect to SignalR, they get a connection ID. You can map the connection ID to real client identity. More info here: Mapping clients to connections
Than in you server method:
Get authenticated client identity
Get signalR hub context
Map client identity to existing signalR connection ID
Send message to that signalR connection
As I can see from you code you might be working on some personal-use/exploratory project and probably not interested in implementing authentication/don't care about security. You could get signalR connection ID in your client after connecting through $.connection.hub.id. Than you could send this ID to the server method as parameter or header. This is by no way should be used in production environment, as you would trust the client who he is, and pass parameters that are not strictly needed by your method.
As to "why":
In fact I don't think you need signalR for your use case. You call a server method, it saves to DB and returns you OK or not OK, client is happy. No need to pass it through signalR.
You do need signalR e.g. when:
- Same client is logged in on several devices and wants to get updates if changes were made on one of them
- Client works on something and another one changes same data. You want to inform the first client.
- Inform your client of an event that was not triggered by him (new notification)
In all this cases you have some kind of authentication and sending signalR message to the right client is not a problem.
Answer to comment below
I have little experience with ajax, i guess it might work. Another idea, if you want to avoid authentication, is a subscription model with SignalR.
You have to find out which specific resources you have, let's say "game" in your case, which have IDs. Than clients, interested in that particular resource, shall subscribe to changes.
All participants of a particular card game instance shall call a hub method defined like this:
public async Task SubscribeToGameChanges(long id)
{
await this.Groups.AddToGroupAsync(this.Context.ConnectionId, Helper.GetGameGroupName(id));
}
public static class Helper
{
public static string GetGameGroupName(long id)
{
return $"Game_{id}";
}
}
Than call it from client. Note the AddToGroupAsync. SignalR shall create a group with given name and add a client to it. If group exists, it will just add another client. So you have a group per game instance with a list of interested clients (players).
Now when a change happens to the game, you notify all your clients by calling from your controller on hub context:
await hubContext.Clients.Groups(Helper.GetGameGroupName(id)).SendAsync("myNotifyMethod", myParameters);
You could pack all your changes into parameters, or just inform the clients that the state of the game (or whatever other resource) has changed and clients shall requery the state through normal API call.
Also I noticed you use GlobalHost in your code. My code samples are for .net core SignalR version and might slightly differ in your case. See here on differences between .net core and full .net SignalR.
I have a MvxViewController and in the ViewDidLoad i bind the button click to the viewmodel. When the button is clicked I open another view in which I will need to return a string back to my first view
public override void ViewDidLoad ()
{
var set = this.CreateBindingSet<MyView1, MyView1ViewModel>();
set.Bind(myButton).To(vm => vm.MyButtonCommand);
set.Apply();
}
public ICommand MyButtonCommand
{
get
{
_myButtonCommand = _myButtonCommand ?? new MvxCommand(MyButtonCommandClick);
return _myButtonCommand;
}
}
private void MyButtonCommandClick()
{
ShowViewModel<ViewModelNumber2>();
}
After some logic is ran in my second view I want to return the string
private void SomeMethodInViewModelNumber2()
{
//Raise event that will get pickup up in MyView
//Or somehow get "SomeString"
if (OnMyResult != null)
OnMyResult ("SomeString");
}
The problem is that I don't want to send the string back using the messenger. I have my reasons but basically because ViewModelNumber2 can be opened from many different places and works slightly different and managing the different messages that would need to be sent back and where to subscribe to these messages would be a mess
Is there any way that I can do something like the below?
public override void ViewDidLoad ()
{
var set = this.CreateBindingSet<MyView1, MyView1ViewModel>();
set.Bind(myButton).To(vm => vm.MyButtonCommand).OnMyResult((myString) => {Process(myString)});
set.Apply();
}
Or perhaps when I create ViewModelNumber2 I should pass a callBack into the constructor and use that to send the string back from ViewModelNumber2 to MyView1ViewModel
ShowViewModel<ViewModelNumber2>(OnMyResult);
What is the best way to do this?
In short: I don't know what "the best way to do this" is.
The area of ChildViewModel-ParentViewModel messages is complicated - especially because on platforms like Android using Activities and WindowsPhone using Pages you have no guarantee that the ParentViewModel will be in memory when the Child is shown. (Note: this isn't a problem on iOS as its "app suspension" model is simpler)
When I do need one ViewModel returning data to another, then:
Often I try to implement the data collection views as "popup dialogs" rather than as "whole pages" - this makes the parent-child ViewModel relationship more correct - and ensures the parent ViewModel will be in memory when the child closes.
Often I recommend people use a Messenger-based technique like Greg describes in: http://www.gregshackles.com/2012/11/returning-results-from-view-models-in-mvvmcross/
often I've done this messaging via background services rather than via ViewModel-ViewModel messaging (a bit like the way screens are updated in https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-17-CollectABull-Part6)
Another solution I've used is to:
implement a IDropBoxService singleton - with an API like void Deposit(key, value) and bool TryCollect(key, out value)
allow the closing "child" ViewModels to leave "values" when they close
implement IVisible functionality in my "parent" ViewModel - like in https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-42-Lifecycles/Lifecycle.Core/ViewModels/FirstViewModel.cs#L10
use the IVisible method to check for messages
To implement anything perfectly, you really should add serialisation code to make sure this all works during "tombstoning" on all platforms... but often this is overkill - for a simple data collection dialog users often don't need "perfect" tombstoning support.
I am working on a website and we will need to send the user some email notifications when some actions happen on the website, such as if someone else sent the user a message or invite him to an event.
Is there a standard good way to attach a notification to any method without changing the method code?
For example I was thinking if I can put an attribute on the method this attribute will make this method to call the notification module with some parameters.
note: I am working on an ASP.Net MVC 3 website, using entity framework codefirst.
I do not believe there is a standard process.
Aspect Oriented approaches (such as attributes) can be handy only if there are used in conjunction with AOP frameworks (such as AspectSharp) or when used on the MVC Action itself: you can use action filters to achieve the requirement and send use the notification if the events are mapped to MVC actions.
Event Listeners. You do have to change the code, but you don't actually send the email within the code.
Basically, any code that does stuff that other code might be interested in has hooks so that listeners can attach to it and listen for events.
In Pseudo-java:
public class OrderProcessor {
protected final List<OrderProcessorListener> listeners = new ArrayList<OrderProcessorListener>();
public void addListener(OrderProcessorListener orderProcessorListener) {
listeners.add(orderProcessorListener);
}
public void notifyListeners(OrderProcessorEvent event) {
for(OrderProcessorListener listener : listeners) {
listener.handle(event);
}
}
public void randomMethod() {
// ... do stuff
notifyListeners(new SomeEvent(...)); // notify listeners
}
public interface OrderProcessorListener {
public void handle(OrderProcessorEvent event);
}
}
then, other interested code can do...
public class EmailSender implements OrderProcessorListener {
public void handleEvent(OrderProcessorEvent event) {
// do whatever...
}
}
When you construct your OrderProcessor and your EmailSender, you then add the EmailSender as a listener and voila. You can use this pattern everywhere you need to react to actions from a piece of code- and you don't need to put the actions in the same code...
Would be pretty hard without any change to the original code. How would you know an action succeeded? And what type of notification should be sent, to whom, etc.
If not changing the original code is a must, you could do it in a hacky way: add a global filter, inspect the controller name, action name, the action result, and maybe you could decide from those parameters if an email should be sent. But this would be extremely fragile, and a maintenance nightmare.
Unless your notifications are extremely simple, like always send e-mail to all event attendees, if any modification is done to the event. But that could cover only some of the basic use-cases...
IMO it would be better if you integrated sending notifications into your existing code. If you extend the meaning of a repository (and you use one) to "take database actions, and anything else related to creation/update/delete of an object".
No changes to controller actions, and your EventRepository.Create/Modify methods would know already have all the parameters to send the notifications...
This link http://msdn.microsoft.com/en-us/library/aa772153(VS.85).aspx says:
You can register up to five notification requests on a single LDAP connection. You must have a dedicated thread that waits for the notifications and processes them quickly. When you call the ldap_search_ext function to register a notification request, the function returns a message identifier that identifies that request. You then use the ldap_result function to wait for change notifications. When a change occurs, the server sends you an LDAP message that contains the message identifier for the notification request that generated the notification. This causes the ldap_result function to return with search results that identify the object that changed.
I cannot find a similar behavior looking through the .NET documentation. If anyone knows how to do this in C# I'd be very grateful to know. I'm looking to see when attributes change on all the users in the system so I can perform custom actions depending on what changed.
I've looked through stackoverflow and other sources with no luck.
Thanks.
I'm not sure it does what you need, but have a look at http://dunnry.com/blog/ImplementingChangeNotificationsInNET.aspx
Edit: Added text and code from the article:
There are three ways of figuring out things that have changed in Active Directory (or ADAM). These have been documented for some time over at MSDN in the aptly titled "Overview of Change Tracking Techniques". In summary: Polling for Changes using uSNChanged. This technique checks the 'highestCommittedUSN' value to start and then performs searches for 'uSNChanged' values that are higher subsequently. The 'uSNChanged' attribute is not replicated between domain controllers, so you must go back to the same domain controller each time for consistency. Essentially, you perform a search looking for the highest 'uSNChanged' value + 1 and then read in the results tracking them in any way you wish. Benefits This is the most compatible way. All languages and all versions of .NET support this way since it is a simple search. Disadvantages There is a lot here for the developer to take care of. You get the entire object back, and you must determine what has changed on the object (and if you care about that change). Dealing with deleted objects is a pain. This is a polling technique, so it is only as real-time as how often you query. This can be a good thing depending on the application. Note, intermediate values are not tracked here either. Polling for Changes Using the DirSync Control. This technique uses the ADS_SEARCHPREF_DIRSYNC option in ADSI and the LDAP_SERVER_DIRSYNC_OID control under the covers. Simply make an initial search, store the cookie, and then later search again and send the cookie. It will return only the objects that have changed. Benefits This is an easy model to follow. Both System.DirectoryServices and System.DirectoryServices.Protocols support this option. Filtering can reduce what you need to bother with. As an example, if my initial search is for all users "(objectClass=user)", I can subsequently filter on polling with "(sn=dunn)" and only get back the combination of both filters, instead of having to deal with everything from the intial filter. Windows 2003+ option removes the administrative limitation for using this option (object security). Windows 2003+ option will also give you the ability to return only the incremental values that have changed in large multi-valued attributes. This is a really nice feature. Deals well with deleted objects. Disadvantages This is .NET 2.0+ or later only option. Users of .NET 1.1 will need to use uSNChanged Tracking. Scripting languages cannot use this method. You can only scope the search to a partition. If you want to track only a particular OU or object, you must sort out those results yourself later. Using this with non-Windows 2003 mode domains comes with the restriction that you must have replication get changes permissions (default only admin) to use. This is a polling technique. It does not track intermediate values either. So, if an object you want to track changes between the searches multiple times, you will only get the last change. This can be an advantage depending on the application. Change Notifications in Active Directory. This technique registers a search on a separate thread that will receive notifications when any object changes that matches the filter. You can register up to 5 notifications per async connection. Benefits Instant notification. The other techniques require polling. Because this is a notification, you will get all changes, even the intermediate ones that would have been lost in the other two techniques. Disadvantages Relatively resource intensive. You don't want to do a whole ton of these as it could cause scalability issues with your controller. This only tells you if the object has changed, but it does not tell you what the change was. You need to figure out if the attribute you care about has changed or not. That being said, it is pretty easy to tell if the object has been deleted (easier than uSNChanged polling at least). You can only do this in unmanaged code or with System.DirectoryServices.Protocols. For the most part, I have found that DirSync has fit the bill for me in virtually every situation. I never bothered to try any of the other techniques. However, a reader asked if there was a way to do the change notifications in .NET. I figured it was possible using SDS.P, but had never tried it. Turns out, it is possible and actually not too hard to do. My first thought on writing this was to use the sample code found on MSDN (and referenced from option #3) and simply convert this to System.DirectoryServices.Protocols. This turned out to be a dead end. The way you do it in SDS.P and the way the sample code works are different enough that it is of no help. Here is the solution I came up with:
public class ChangeNotifier : IDisposable
{
LdapConnection _connection;
HashSet<IAsyncResult> _results = new HashSet<IAsyncResult>();
public ChangeNotifier(LdapConnection connection)
{
_connection = connection;
_connection.AutoBind = true;
}
public void Register(string dn, SearchScope scope)
{
SearchRequest request = new SearchRequest(
dn, //root the search here
"(objectClass=*)", //very inclusive
scope, //any scope works
null //we are interested in all attributes
);
//register our search
request.Controls.Add(new DirectoryNotificationControl());
//we will send this async and register our callback
//note how we would like to have partial results
IAsyncResult result = _connection.BeginSendRequest(
request,
TimeSpan.FromDays(1), //set timeout to a day...
PartialResultProcessing.ReturnPartialResultsAndNotifyCallback,
Notify,
request);
//store the hash for disposal later
_results.Add(result);
}
private void Notify(IAsyncResult result)
{
//since our search is long running, we don't want to use EndSendRequest
PartialResultsCollection prc = _connection.GetPartialResults(result);
foreach (SearchResultEntry entry in prc)
{
OnObjectChanged(new ObjectChangedEventArgs(entry));
}
}
private void OnObjectChanged(ObjectChangedEventArgs args)
{
if (ObjectChanged != null)
{
ObjectChanged(this, args);
}
}
public event EventHandler<ObjectChangedEventArgs> ObjectChanged;
#region IDisposable Members
public void Dispose()
{
foreach (var result in _results)
{
//end each async search
_connection.Abort(result);
}
}
#endregion
}
public class ObjectChangedEventArgs : EventArgs
{
public ObjectChangedEventArgs(SearchResultEntry entry)
{
Result = entry;
}
public SearchResultEntry Result { get; set;}
}
It is a relatively simple class that you can use to register searches. The trick is using the GetPartialResults method in the callback method to get only the change that has just occurred. I have also included the very simplified EventArgs class I am using to pass results back. Note, I am not doing anything about threading here and I don't have any error handling (this is just a sample). You can consume this class like so:
static void Main(string[] args)
{
using (LdapConnection connect = CreateConnection("localhost"))
{
using (ChangeNotifier notifier = new ChangeNotifier(connect))
{
//register some objects for notifications (limit 5)
notifier.Register("dc=dunnry,dc=net", SearchScope.OneLevel);
notifier.Register("cn=testuser1,ou=users,dc=dunnry,dc=net", SearchScope.Base);
notifier.ObjectChanged += new EventHandler<ObjectChangedEventArgs>(notifier_ObjectChanged);
Console.WriteLine("Waiting for changes...");
Console.WriteLine();
Console.ReadLine();
}
}
}
static void notifier_ObjectChanged(object sender, ObjectChangedEventArgs e)
{
Console.WriteLine(e.Result.DistinguishedName);
foreach (string attrib in e.Result.Attributes.AttributeNames)
{
foreach (var item in e.Result.Attributes[attrib].GetValues(typeof(string)))
{
Console.WriteLine("\t{0}: {1}", attrib, item);
}
}
Console.WriteLine();
Console.WriteLine("====================");
Console.WriteLine();
}