Anybody here has actually implemented any logging strategy when application is running as XBAP ? Any suggestion (as code) as to how to implement a simple strategy base on your experience.
My app in desktop mode actually logs to a log file (rolling log) using integrated asop log4net implementation but in xbap I can't log cause it stores the file in cache (app2.0 or something folder) so I check if browser hosted and dont log since i dont even know if it ever logs...(why same codebase)....if there was a way to push this log to a service like a web service or post error to some endpoint...
My xbap is full trust intranet mode.
I would log to isolated storage and provide a way for users to submit the log back to the server using either a simple PUT/POST with HttpWebRequest or, if you're feeling frisky, via a WCF service.
Keep in mind an XBAP only gets 512k of isolated storage so you may actually want to push those event logs back to the server automatically. Also remember that the XBAP can only speak back to it's origin server, so the service that accepts the log files must run under the same domain.
Here's some quick sample code that shows how to setup a TextWriterTraceListener on top of an IsolatedStorageFileStream at which point you can can just use the standard Trace.Write[XXX] methods to do your logging.
IsolatedStorageFileStream traceFileStream = new IsolatedStorageFileStream("Trace.log", FileMode.OpenOrCreate, FileAccess.Write);
TraceListener traceListener = new TextWriterTraceListener(traceFileStream);
Trace.Listeners.Add(traceListener);
UPDATE
Here is a revised answer due to the revision you've made to your question with more details.
Since you mention you're using log4net in your desktop app we can build upon that dependency you are already comfortable working with as it is entirely possible to continue to use log4net in the XBAP version as well. Log4net does not come with an implementation that will solve this problem out of the box, but it is possible to write an implementation of a log4net IAppender which communicates with WCF.
I took a look at the implementation the other answerer linked to by Joachim Kerschbaumer (all credit due) and it looks like a solid implementation. My first concern was that, in a sample, someone might be logging back to the service on every event and perhaps synchronously, but the implementation actually has support for queuing up a certain number of events and sending them back to the server in batch form. Also, when it does send to the service, it does so using an async invocation of an Action delegate which means it will execute on a thread pool thread and not block the UI. Therefore I would say that implementation is quite solid.
Here's the steps I would take from here:
Download Joachim's WCF appender implementation
Add his project's to your solution.
Reference the WCFAppender project from your XBAP
Configure log4net to use the WCF appender. Now, there are several settings for this logger so I suggest checking out his sample app's config. The most important ones however are QueueSize and FlushLevel. You should set QueueSize high enough so that, based on how much you actually are logging, you won't be chattering with the WCF service too much. If you're just configuring warnings/errors then you can probably set this to something low. If you're configuring with informational then you want to set this a little higher. As far as FlushLevel you should probably just set this to ERROR as this will just guarantee that no matter how big the queue is at the time an error occurs everything will be flushed at the moment an error is logged.
The sample appears to use LINQ2SQL to log to a custom DB inside of the WCF service. You will need to replace this implementation to log to whatever data source best suits your needs.
Now, Joachim's sample is written in a way that's intended to be very easy for someone to download, run and understand very quickly. I would definitely change a couple things about it if I were putting it into a production solution:
Separate the WCF contracts into a separate library which you can share between the client and the server. This would allow you to stop using a Visual Studio service reference in the WCFAppender library and just reference the same contract library for the data types. Likewise, since the contracts would no longer be in the service itself, you would reference the contract library from the service.
I don't know that wsHttpBinding is really necessary here. It comes with a couple more knobs and switches than one probably needs for something as simple as this. I would probably go with the simpler basicHttpBinding and if you wanted to make sure the log data was encrypted over the wire I would just make sure to use HTTPS.
My approach has been to log to a remote service, keyed by a unique user ID or GUID. The overhead isn't very high with the usual async calls.
You can cache messages locally, too, either in RAM or in isolated storage -- perhaps as a backup in case the network isn't accessible.
Be sure to watch for duplicate events within a certain time window. You don't want to log 1,000 copies of the same Exception over a period of a few seconds.
Also, I like to log more than just errors. You can also log performance data, such as how long certain functions take to execute (particularly out-of-process calls), or more detailed data in response to the user explicitly entering into a "debug and report" mode. Checking for calls that take longer than a certain threshold is also useful to help catch regressions and preempt user complaints.
If you are running your XBAP under partial trust, you are only allowed to write to the IsolatedStorage on the client machine. And it's just 512 KB, which you would probably want to use in a more valuable way (than for logging), like for storing user's preferences.
You are not allowed to do any Remoting stuff as well under partial trust, so you can't use log4net RemotingAppender.
Finally, under partial trust XBAP you have WebPermission to talk to the server of your app origin only. I would recommend using a WCF service, like described in this article. We use similar configuration in my current project and it works fine.
Then, basically, on the WCF server side you can do logging to any place appropriate: file, database, etc. You may also want to keep your log4net logging code and try to use one of the wcf log appenders available on the internets (this or this).
Related
I'm building a vClould client application via the REST APIs, however, the documentation is inconsistent an in some cases just wrong and misleading.
All I really need is a solid debug tool or even a log file. Any recommendations?
You already mentioned you have access to the message stream, which is one of the first steps. Typically if I'm using the Apache HttpClient/HttpComponents I'll go increase the log level so it logs the full HTTP requests.
My next step is usually to cheat and to log into vCD as a system administrator and see what's going on. When vCD was designed there was a very deliberate decision to not reveal infrastructure level problems to tenants of the cloud (normal org users or org admins), as that would break the cloud abstraction. Sadly, that means as an org-level user you're often going to get "contact your cloud admin" error responses. We are aware that this isn't ideal and try to find ways to make it better when we can (IIRC the new 5.5 release that was announced last month does have some improvements in that area).
The last step is usually to cheat even more and to look at the server side logs (vcloud-container-debug.log, specifically). That usually gives me a better clue as to what went wrong. Of course, you may be unlucky and not have access to the vCD cell machine.
My workaround in the latter two cases is to try the operations via the vCD UI and see (1) if they work as expected and (2) if they do, to check the system state via the API and see if I'm sending the wrong request payloads, etc. because the doc or schema reference may not have been clear enough.
In regards to the documentation, please use the feedback links () found on individual doc pages to let us know! Our technical writer reviews all the feedback and tries to address them.
My final suggestion is that you might want to post API questions to the vCloud API community forum VMware has. There are a number of experts (both users and VMware employees) that monitor it and respond to questions.
I use a self hosted service within a WPF application for certain tasks. The service host is started at runtime and its base address is http://localhost:Whatever-port-is-free-at-runtime. This works fine when the user has admin rights but problems arise when the application is ran by a restricted user.
I found some suggestions on the web that suggested reserving the url using netsh/httpcfg which works fine for admin users but fails for restricted users because they presumably do not have the rights to use these tools to reserve a url. As the port number is not known until runtime the url reservation command can logically only be run at runtime which means the process will be initiated by a restricted user without the right privilege to execute the command. Am i correct in thinking this?
What i would like to know is if there is a suitable work around? Also, i would like to know if a restricted user can open a locally hosted WCF service at all, since solving the aforementioned problem will be pointless if the restricted user couldn't do this.
This question perfectly describes my first issue of URL reservation
In WCF, the HTTP and HTTPS bindings use HTTP.sys under the cover to reserve a required URL for a specific WCF service, which is the same path IIS itself follows while doing the bindings for the websites it manages. This explains why the process performing the HTTP/HTTPS binding is required to run in elevated mode.
That being said, I would solve your issue in two different ways:
Option 1: use a different kind of binding. NetTcpBinding and NetNamedPipesBinding, for example, do not generally require administrative privileges: this is by far the easiest way to go.
Option 2: setup the required namespace reservation at installation time. This way you may ask your users to perform the installation in elevated mode and later allow restricted accounts to run it. While performing the initial installation/reservation you may also find out an available port to use (and perhaps save it in a configuration file for later reuse).
I'm not really sure how to handle the scenario I have in a good code manner.
The basic of the criteria of my work is this:
A WPF application that consumes a WCF service
The service uses per session instancing
The session starts soon after application is started and should live through the application lifetime (with small exceptions)
Some method calls in a session must precede and be finished before others are called
This means I will have to be able to have one instance of a proxy client throughout the whole application. I will also have to be able to handle async calls, so the client won't hang up, but at the same time ensure they are finished.
My technical understanding go WCF is limiting enough to not know if certain scenarios would work as intended. So I'm going to list my uncertainties:
When does a session start and when does it end. Is it based on the creation of clients or could a separate client instance access the same session if the first would go faulted.
What is the best way to handle exceptions through a WCF service
Is ChannelFactory something I should look at to help me put here.
So what I did in the first iteration to try to solve some of these problems.
I used dependency injection to inject the client instance throughout the classes of my WPF application (I'm using MVVM) to ensure the same instance is everywhere.
I made the service reference using the asynchronous generation method to get the Begin and End versions of all methods to ensure the calls would be async
I used the Coroutine (IResult interface) feature of the Caliburn.Micro framework to ensure one async action is finished before the other begins (have no idea if this is a proper usage or if it is a smart move at all).
Problems I still have is of course how to handle a faulted state of the client. I'm assuming right now that I could reinstance the client and either rescue the session or I could actually just set it up again as it was. I now need to reinstance it everyplace I injected it in with the same new instance.
So I though perhaps it would be best to create a ClientManager class that would wrap the Client. That way I could inject this ClientManager and reinstance inside of him if needed. I guess I should expose him outwards to be able to make method calls but it would be great if I could error handle inside him in somehow. I'm just having a hard time testing my methods and I'm never certain it will work properly in integration because I don't understand all of the inner workings of WCF, coroutines and threading.
Is there anyone out there with more experience then me in these matters that could give me a few pointers or at least tell me how WCF works in these situations ( per session ) and what I'm doing wrong and what right.
WCF supports sessions out-of-box, so I would recommend starting with this MSDN article.
At a very high level, first you set SessionMode=SessionMode.Required in your ServiceContract. And then, set the IsInitiating=True and IsTerminating=True properties on your OperationContract's to mark the start and end of each session.
However, note that WCF limits concurrent sessions by default to 16 to prevent DOS attacks, but you can always up the value. Also, you would have realized that the session is valid as long as its host (IIS / Windows Service / other) is not recycled.
On a related note, I have used WCF Durable Services earlier - which are meant to persist the state of your WCF service in a data-store (default is SQL Server). Ofcourse, there is a performance hit here. Suggest reading further to see if this is the right choice for you.
Hope this helps.
following on from this question:
GWT detect GAE version changes and reload
I would like to further clarify some things.
I have an enterprise app (GWT 2.4 & GAEJ 1.6.4 - using GWT-RPC) that my users typically run all day in their browsers, indeed some don't bother refreshing the browser from day to day. I make new releases on a pretty regular basis, so am trying to streamline the process for minimal impact to my users. - Not all releases concern all users, so I'd like to minimize the number of restarts.
I was hoping it might be possible to do the following. Categorize my releases as follows:
1) releases that will cause an IncompatibleRemoteServiceException to be thrown
and 2) those that don't : i.e. only affect the server, or client but not the RPC interface.
Then I could make lots of changes to the client and server without affecting the interface between the two. As long as I don't make a modification to the RPC interface, presumably I can change server code and or client code and the exception won't be thrown? Right? or will any redeployment of GAE cause an old client to get an IncompatibleRemoteServiceException ?
If I was able to do that I could batch up interface busting changes into fairly infrequent releases and notify my users a restart will be required.
many thanks for any help.
I needed an answer pretty quick so I thought I'd just do some good old fashioned testing to see what's possible. Hopefully this will be useful for others with production systems using GWT-RPC.
Goal is to be able to release updates / fixes without requiring all connected browsers to refresh. Turns out there is quite a lot you can do.
So, after my testing, here's what you can and can't do:
no problem
add a new call to a RemoteService
just update some code on the server e.g. simple bug fix, redeploy
just update some client (GWT) code and redeploy (of course anyone wanting new client functionality will have to refresh browser, but others are unaffected)
limited problems
add a parameter to an existing RemoteService method - this one is interesting, that particular call will throw "IncompatibleRemoteServiceException" (of course) but all others calls to the same Remote Service or other Remote Services (Impl's) are unaffected.
Add a new type (as a parameter) to any method within a RemoteService - this is the most interesting one, and is what led me to do this testing. It will render that whole RemoteService out of date for existing clients with IncompatibleRemoteServiceException. However you can still use other RemoteServices. - I need to do some more testing here to fully understand or perhaps someone else knows more?
so if you know what you're doing you can do quite a lot without having to bother your users with refreshes or release announcements.
I have a GWT app, which is deployed on the app engine. The application is basically an exam simulator. All the exam questions and answers are stored in an XML file on the server. I use JAXB parser to parse the XML file and send a list of objects to the client through GWT RPC.
I noticed that during the transit (server -> client), the entire data is visible in plain text in Firebug. Since the data (exam questions and answers) are my intellectual property (IP) and something that I give lot of value to, I'm concerned that it's very easy to steal that data. Therefore, I'm trying to find ways to do some basic encryption and obfuscate the content when it's being sent over from the server to the client.
After Googling, I came across gwt-crypto project, and within a few minutes, I was able to achieve the exact result that I wanted. The server would encrypt the data, and the client would decrypt it. In Firebug, it would show the data in encrypted format, and not as plain text.
However, I ran into an issue. After implementing encryption/decryption, I noticed that my application would not load inside my company's network, which is obviously protected by a firewall. The application works perfectly from home or even on a 3G network on my phone. Another version of the application, which does not use encryption/decryption works perfectly from within my company's network. I confirmed this by creating 2 exact same versions of the app, with the only difference between a boolean flag, that determines whether encryption/decryption is enabled or disabled.
I have the following questions here:
What is the best way to achieve the result that I want to achieve? Is gwt-crypto a good solution for that? I'm fine with any simple approach to obfuscate the data during transit. It doesn't have to be a sophisticated algorithm.
What could be the possible reason for a GWT app, with encryption/decryption enabled, not working inside a firewall? I'm really clueless on this.
I'll appreciate any help on this issue.
Using SSL is the right way to go.
In your case, given AppEngine SSL limitations, you should load your HTML normally from non-SSL domain and use cross-site RPC to load your data via SSL domain.
Update:
What is the best way to achieve the result that I want to achieve?
If you want to secure the data in transit then the only secure option is SSL/HTTP. Usually it's also the simplest one as it does not require you to change the application code, just server configuration. In your particular case (appengine with private domain), it takes more work as described above.
Is gwt-crypto a good solution for that?
No. gwt-crypto uses a key to encrpt/decrypt the data. You also need a secure way to discribute this key.
I'm fine with any simple approach to obfuscate the data during transit.
Security through obscurity in not security. It's a false sense of security, which is even more dangerous than no security. It's enough that only one of the technically capable students cracks this and soon everybody would do it.
Possible attack would go like this:
Snoop the network, get username/password of user.
Login as that user, have browser load exam data, which is now unencrypted in memory.
Dump the DOM and inspect it for exam questions.
-
What could be the possible reason for a GWT app, with encryption/decryption
enabled, not working inside a firewall?
Use firebug to make sure network connections are identical, except for the encrypted content. Firewalls should not work that deep. Talk to sysadmin about it.