I have been researching this issue for long. But I haven't come across any satisfying solution.
The scenario is that I have a WPF client application. I have a couple of web references added to the project and I Settings.Designer.cs file was modified and had a hard coded reference to the srever url and port. This started getting reflected in my app.config file in ApplicationSettings section.
Before the user logs in, he can specify the settings for the ServerIP and Port for the server. Now I would like to save these settings in app.config and get the value for server IP and port picked up from there or save it elsewhere and connect to the server through this IP and Port. I would like these changes to persist.
One solution that I could think of was to read the app.config through an XML reader, modify the file, save it and restart the application somehow.
I am not able to think of a better scenario as I think ApplicationSettings section can not be modified from inside the application.
EDIT:
My applicationSettiings section looks something like this:
<applicationSettings>
<ApplicationName.Properties.Settings>
<setting name="Web_Service_Reference_Name1" serializeAs="String">
<value>http://10.1.100.118:8080/AD/WebService1</value>
</setting>
<setting name="Web_Service_Reference_Name2" serializeAs="String">
<value>http://10.1.100.118:8080/AD/WebService2</value>
</setting>
</ApplicationName.Properties.Settings>
</applicationSettings>
Sometimes ago a similar question was posted on this site.
I have a simple solutions that looks like this:
public void WriteLocalValue(string localKey, string curValue)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
KeyValueConfigurationElement k = config.AppSettings.Settings[localKey];
if (k == null)
config.AppSettings.Settings.Add(localKey, curValue);
else
k.Value = curValue;
config.Save();
}
public string ReadLocalValue(string localKey, string defValue)
{
string v = defValue;
try
{
Configuration config = ConfigurationManager.OpenExeConfiguration( Application.ExecutablePath);
KeyValueConfigurationElement k = config.AppSettings.Settings[localKey];
if (k != null) v = (k.Value == null ? defValue : k.Value);
return v;
}
catch { return defValue; }
}
Related
I am trying to make a XBAP application communicating with a webservice with login.
But I want the user to skip the login step if they already logged in the last seven days.
I got it to work using html/aspx.
But it fails continuously with XBAP.
While debugging, the application is given full trust.
This is the code I have so far to write the cookie:
protected static void WriteToCookie(
string pName,
Dictionary<string, string> pData,
int pExiresInDays)
{
// Set the cookie value.
string data = "";
foreach (string key in pData.Keys)
{
data += String.Format("{0}={1};", key, pData[key]);
}
string expires = "expires=" + DateTime.Now.AddDays(pExiresInDays).ToUniversalTime().ToString("r");
data += expires;
try
{
Application.SetCookie(new Uri(pName), data);
}
catch (Exception ex)
{
}
}
And this is what I have to read the cookie:
protected static Dictionary<string, string> ReadFromCookie(
string pName)
{
Dictionary<string, string> data = new Dictionary<string, string>();
try
{
string myCookie = Application.GetCookie(new Uri(pName));
// Returns the cookie information.
if (String.IsNullOrEmpty(myCookie) == false)
{
string[] splitted = myCookie.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
string[] sub;
foreach(string split in splitted)
{
sub = split.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (sub[0] == "expires")
{
continue;
}
data.Add(sub[0], sub[1]);
}
}
}
catch(Exception ex)
{
}
return data;
}
The pName is set with:
string uri = "http://MyWebSiteName.com";
When the user authenticate the first time, I call the WriteToCookie function and set it with 7 days to expire.
It looks like everything is fine as I get no exception of error messages. (I have a break point in the catch)
After that, I close the session and start it again.
The first thing I do is a ReadFromCookie.
Then I get an exception with the following message: No more data is available
So my application is sending the user automatically back to the login screen.
I also tried to do a ReadFromCookie right after the WriteToCookie in the same session, and I get the same error.
Application.SetCookie(new Uri("http://MyWebSiteName.com/WpfBrowserApplication1.xbap"), "Hellllo");
string myCookie2 = Application.GetCookie(new Uri("http://MyWebSiteName.com/WpfBrowserApplication1.xbap"));
It seems to me that the cookie is not even written in the first place.
So I am guessing I am doing something wrong.
Maybe the uri I am using is wrong. Is there a specific format needed for it?
Just like you need a very specific format for the expire date.
I have been searching quite a lot of internet for a good sample/tutorial about using cookies with XBAP, and I could not find anything really well documented or tested.
A lot of people say that it works, but no real sample to try.
A lot of people also handle the authentication in html, then go to the XBAP after successfully reading/writing the cookies.
I would prefer a full XBAP solution if possible.
To answer some questions before they are asked, here are the project settings:
Debug:
Command line arguments: -debug -debugSecurityZoneURL http://MyWebSiteName.com "C:\Work\MyWebSiteName\MyWebSiteNameXBAP\bin\Debug\MyWebSiteNameXBAP.xbap"
Security:
Enable ClickOnce security settings (Checked)
This is a full trust application (selected)
I also created a certificate, and added it the 3 stores like explained in "publisher cannot be verified" message displayed
So I do not have the warning popup anymore. I just wanted to make sure that it was not a permission issue.
Finally found the answer to this problem.
Thanks for this CodeProject I was finally able to write/read cookies from the XBAP code.
As I had guessed, the URI needs to be very specific and you cannot pass everything you want in it.
What did the trick was using: BrowserInteropHelper.Source
In the end the read/write code looks like:
Application.SetCookie(BrowserInteropHelper.Source, data);
string myCookie = Application.GetCookie(BrowserInteropHelper.Source);
It looks like you cannot use ';' to separate your own data.
If you do so, you will only get the first entry in your data.
Use a different separator (ex: ':') and then you can get everything back
The data look like this:
n=something:k=somethingElse;expires=Tue, 12 May 2015 14:18:56 GMT ;
The only thing I do not get back from Application.GetCookie is the expire date.
Not sure if it is normal or not. Maybe it is flushed out automatically for some reason. If someone knows why, I would appreciate a comment to enlighten me.
At least now I can read/write data to the cookie in XBAP. Yeah!
I have created a new Surface controller for use with my Umbraco 7.1.8 installation. My code is as follows:
public class EnquiryController : SurfaceController
{
ILog Log = LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType
);
[HttpPost]
public ActionResult Submit(EnquiryModel model)
{
if (!ModelState.IsValid)
return CurrentUmbracoPage();
// Create a regular expression to remove script tags
Regex regex = new Regex(#"<script(.+?)*</script>");
string request = regex.Replace(model.Message, string.Empty);
request = request + "<br/><br/>" + "Phone: " + model.Telephone + "<br/><br/>" + "Email: " + model.Email;
MailMessage message = new MailMessage();
message.From = new MailAddress(model.Email);
message.To.Add(new MailAddress("info#axumtech.com"));
message.Subject = "New Website Enquiry - " + model.Name;
message.Body = request;
SmtpClient client = new SmtpClient();
try
{
client.Send(message);
TempData["success"] = true;
}
catch (Exception ex)
{
TempData["error"] = true;
Log.Debug("Custom Error - " + ex.Message);
return CurrentUmbracoPage();
}
return RedirectToCurrentUmbracoPage();
}
}
My problem is my code fails to send the Email and simply performs the CurrentUmbracoPage() method call.
To counteract this and find out what the issue is I have attempted to log the Exception that is generated using Log4Net however this does not appear to be working as nothing is written to the standard Umbraco log.
This is all occuring on a live server. I have published my development code using Visual Studio 2013 and then uploaded this published site to the server via FTP ensuring that the correct SMTP detals are entered into the Web.Config.
The one thing that concerns me and could be a cause of this issue is that this publish process seems to omit the /Controllers and /Models folders from my solution despite the actually being a part of the project. Is this an issue or are these compiled in .dlls?
To me it seems rather odd that the controllers folder is omitted and could potentially explain why the Email is not being sent..
Have you built your project? Your controllers are compiled into a dll so do not need to be included in the published site.
If you are still building this page then get rid of the try catch and turn custom errors off so you get the ysod - you want this page to fail with direc feedback
However, to get logging working:
At the top create using ref
using Umbraco.Core.Logging
In the catch:
LogHelper.Error(MethodBase.GetCurrentMethod().DeclaringType, ex.ToString(), ex)
It seems you have a problem in your log4net configuration (are you calling XmlConfigurator.Configure?). The easiest way to solve this is to enable internal logging to see what is wrong:
enable the internal logging:
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
Set the output location:
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add name="textWriterTraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="C:\tmp\log4net.txt" />
</listeners>
</trace>
</system.diagnostics>
This issue was caused by an error in my model. The model parameter was marked as an int but a text string was being sent through to it by the form. Because of this the model was always invalid and therefore would redirect the page before it ever hit the logging.
I have created a C sharp Wpf ClickOnce application which uses xml rpc for communincation. A lot of my users get there proxy settings in different ways. Some use a pac file, other from IE or dhcp etc. I want to automate this whole process of getting the proxy details in any kind of environment. I have tried a LOT of different code snippets but want to hear if something like this already exists.
I see the Xml Rpc documentation has a setProxy method but I'm not sure how to specify the username or passsword if one is used. This whole process is still a little bit confusing for me.
I have also tried many different pieces of code including the WebProxy Class and using DefaultCredentials,DefaultProxy,GetSystemWebProxy etc.
At the moment I'm going to try a dllimport using winhttp to get the proxy settings. I am not sure if one can do this in a Clickonce Deployment. Is the dllimport the same as p/invoke ?
As you can see I would appreciate some advice on how to go about getting ANY type of proxy setting.
Appreciate any feedback.
ClickOnce installation/update doesn't really support proxy authentication. It will use the information in IE, and sometimes the machine.config file. The definitive thread with all known information about this is here.
I haven't had have problems with proxy authentication from the standpoint of installing applications. When using our application, which called backend WCF services, we let the user provide his proxy authentication information, and we applied the settings programmatically when making the service calls. This has nothing to do with ClickOnce.
This worked for me :
public static IExample ProxyAndCredentials { get; set; }
public static string ProxyUrl { get; set; }
public static void SetupProxyAndCredentials() {
//Insert your website here where XmlRpc calls should go
var url = new Uri("http://www.example.com/");
try
{
ProxyUrl = WebRequest.DefaultWebProxy.GetProxy(url).ToString();
Log.Debug(url + " is using proxy " + ProxyUrl);
if (ProxyUrl == url.ToString() || ProxyUrl == url + "/"){
// A proxy is not in use here
ProxyUrl = "";
Log.Debug("No proxy is used for " + url);
}
else if (!String.IsNullOrEmpty(ProxyUrl)){
// A proxy is in use
ProxyAndCredentials.Proxy = new WebProxy(ProxyUrl);
Log.Debug("A proxy is used for " + url);
}
//Set credentials, in my experience it is better to always set these
ProxyAndCredentials.Credentials = CredentialCache.DefaultNetworkCredentials;
ProxyAndCredentials.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
}
catch (Exception p)
{
//Handle Exception
}
}
Ok so, basically my problem is with reading and XML file from IsolatedFileStorage. I'll go through the process that leads to my error and then I'll list the relevant code and XML file.
On the first execution it recognises that the file does not exist - it therefore creates the file in IsolatedFileStorage
On the second execution it can now see that the file does exist and so it loads the XML file
On the third execution it can see that it exists - but it throws an XML error
I cannot for the life of me find a solution to it (link to other discussion on MSDN here)
So the code for reading/creating the XML file in IsolatedFileStorage is as follows:
try
{
/***********************
* CHECK THE SETTINGS
********************/
if (store.FileExists("AppSettings.xml"))
{
streamSettings = new IsolatedStorageFileStream("AppSettings.xml", System.IO.FileMode.Open, store);
DebugHelp.Text = "AppSettings.xml exists... Loading!";
streamSettings.Seek(0, System.IO.SeekOrigin.Begin);
xmlDoc = XDocument.Load(streamSettings, LoadOptions.None);
}
else
{
streamSettings = new IsolatedStorageFileStream("AppSettings.xml", System.IO.FileMode.Create, store);
DebugHelp.Text = "AppSettings.xml does not exist... Creating!";
xmlDoc = XDocument.Load("AppSettings.xml", LoadOptions.None);
}
if (xmlDoc != null)
xmlDoc.Save(streamSettings);
}
catch (Exception e)
{
DebugHelp.Text = e.ToString();
}
finally
{
streamSettings.Close();
}
And the related XML file is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<Settings>
</Settings>
Extremely advanced I know - however it throws the following error (here) and you can find the full error text at the bottom of the Social.MSDN page.
Please help - I have been looking for a solution (as the one on the social.msdn site didn't work) for about 2 weeks now.
Why don't you try to read file using a simple StreamReader ? Below a part of a method I have created to readfile from store. Have a try, check your content, and then try loading xml from String (XDocument.Parse etc ...)
String fileContent = String.Empty;
using (_store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (_store.FileExists(file))
{
_storeStream = new IsolatedStorageFileStream(file, FileMode.Open, _store);
using (StreamReader sr = new StreamReader(_storeStream))
{
fileContent = sr.ReadToEnd();
}
__storeStream.Close();
return fileContent;
}
else {
return null;
}
}
It looks to me like the problem is in your save method - it looks like you are maybe appending the settings each time you close - to overwrite your existing settings, you need to ensure that you delete your existing file and create a new one.
To help debug this, try using http://wp7explorer.codeplex.com/ - this might help you see the raw file "on disk"
As an aside, for settings in general, do check out the AppSettings that IsolatedStorage provides by default - unless you have complicated needs, then these may suffice on their own.
Your code sample isn't complete so it's hard to say for sure but, rather than just seeking to the start of the file you may find it easier to just delete it if it already exists. You can do this with FileMode.Create. In turn this means you can do away with the need to check for the existing file.
I suspect that the problem is that you are writing a smaller amount of text to the file on subsequent attempts and so leaving part of the original/previous text behind. In turn this creates a file which contains invalid XML.
It seems that HttpWebRequest caching in WP7 is enabled by default, how do I turn it off?
Adding a random
param url + "?param=" + RND.Next(10000) works, but it's quite tricky and I'm not sure if it will work
with all servers.
For future reference , this worked for me ( I could not use additional query parameter due to project requirements) :
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
if (request.Headers == null)
{
request.Headers = new WebHeaderCollection();
}
request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString();
In case of HttpClient (Portable for Windows Phone) "Cache-Control": "no-cache" on server side works only sometimes. And I cannot add query string random value to RESTful api call as well.
Solution from #frno works good and looks like for HttpClient:
client.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow;
Thank you.
How do you know it's the phone, not the server (or a proxy somewhere between) which is caching?
Have you checked this with Fiddler2 (or equivalent)?
Have you tried setting headers to disable caching?
Something like:
myRequest = (HttpWebRequest)WebRequest.Create(myUri);
myRequest.Headers["Cache-Control"] = "no-cache";
myRequest.Headers["Pragma"] = "no-cache";
We've seen the same behaviour with Silverlight hosted in Chrome.
We add a "?nocache=" + DateTime.Now.Ticks.ToString() to our request URLs if we want to prevent caching.
I found 3 ways
Add a random Query String to the end of your URI (think Guid.NewGuid()) this will avoid caching on the client as the Query String will be different each time
string uri = "http://host.com/path?cache="+Guid.NewGuid().ToString();
Specify no cache in the OutgoingResponse header within your WCF service operation:
var __request = (HttpWebRequest)WebRequest.Create(url.ToString());
if (__request.Headers == null)
__request.Headers = new WebHeaderCollection();
__request.Headers.Add("Cache-Control", "no-cache");
markup your service operation with the AspNetCacheProfile attribute:
[AspNetCacheProfile("GetContent")]
public ResultABC GetContent(string abc)
{
__request = (HttpWebRequest)WebRequest.Create(abc);
return __request;
}
And update your web.config
<system.web>
<caching>
<outputCache enableOutputCache="true" />
<outputCacheSettings>
<outputCacheProfiles >
<add name="GetContent" duration="0" noStore="true" location="Client" varyByParam="" enabled="true"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
...
</system.web>
Adding random number is not bad and it will work. I have used Time (in ajax call). Was placed in the url like a folder.
Yes is possible... :) I spend one week of Experiment and the answer is really simple :
HttpWebRequest _webRequest = WebRequest.CreateHttp(_currentUrl);
_webRequest.AllowReadStreamBuffering = false
_webRequest.BeginGetResponse(_onDownload,
userState);