Server Variables not making it from my ASP page to my Silverlight App - silverlight

I have a basic .ASP page like this, which when hit redirects the user to my SL app after adding a value to the session variables
<!-- Default.htm -->
<html>
<%Session("valuekey")=somevalue%>
<Head>
<META http-equiv="Refresh" content="0; URL=/appdirectory/myapp.aspx?lsv=true"></HEAD>
<Body></Body>
</HTML>
When I get to my SL app hosted on myapp.aspx, the first think it does it check for the lsv QueryString. If it equals true, it calls a WCF service with code like
object x = HttpContext.Current.Session["valuekey"];
if(x == null)
{
ServiceError.Message = "No session variable found";
}
else
{
return x.ToString();
}
Does anyone know why the session variable that I just added on the ASP page before the redirect no longer exists when my SL app tried to fetch it?

This answer assumes there is a good reason why ASP classic enters into the equation in the first place. Perhaps its because Silverlight is being introduced into an existing ASP site. The problem is that most Silverlight Client-Server examples involve .NET WCF on the server.
The answer to your problem is don't use a WCF service to fetch your session data. Use a simple ASP page instead. It should be fairly straight-forward to use a simple XML structure to carry the session data you want to the Silverlight app. Use a DTO class that can be used to deserialise the XML into a simple class. Something like this:
(Caveat: air code)
<%
Dim dom: Set dom = CreateObject("MSXML2.DOMDocument.3.0")
dom.loadXML "<SessionData />"
AddElem dom.documentElement, "ValueKey", Session("valuekey")
AddElem dom.documentElement, "SomeOtherValue", Session("othervalue")
''# include other session values needed by client here.
Response.ContentType = "text/xml"
Response.CharSet = "utf-8"
dom.save Response
Sub AddElem(parent, name, value)
Dim elem: Set elem = parent.ownerDocument.createElement(name)
parent.appendChild elem
elem.text = value;
End Sub
%>
In Silverlight:
[DataContract]
public class SessionData
{
[DataMember(Order=1)]
public string ValueKey {get; set; }
[DataMember(Order=2)]
public string SomeOtherValue {get; set; }
public static void Fetch(Action<string> returnResult, Action<exception> fail)
{
WebClient client = new WebClient();
OpenReadCompletedEventHandler eh = null;
eh = (s, args) =>
{
try
{
var sr = new DataControlSerializer(typeof(SessionData));
returnResult((SessionData)sr.ReadObject(args.Result));
}
catch (Exception e)
{
fail(e);
}
finally
{
client.OpenReadAsyncCompleted -= eh;
}
};
client.OpenReadAsyncCompleted += eh;
client.OpenReadAsync(new Uri("../serviceFolder/sessionState.asp", UriKind.Relative));
}
}
Now in some UI or ViewModel you do
void SessionData_Available(SessionData sessionData)
{
_sessionData = sessionData;
// Other actions needed once session data has arrived.
}
void ReportProblem(Exception e)
{
// Some UI change to inform user of failed fetch
}
...
SessionData.Fetch(SessionData_Available, ReportProblem);

Your asp.net session variables are not available to Silverlight. They live in the server only.
Check this simple workaround. It might help you.

Related

CefSharp.Wpf: Open csv, mailto and pdf with Process.Start(...)

I need to handle different content types from f:///. My application renders offline websites in a WPF application. Everything is working except for links to other content files (csv, mailto and pdf).
If I register a CefCustomScheme for "mailto", then I get the ProcessRequestAsync and can run the Process.Start(...). However another blank window also popup.
If I then add a second CefCustomScheme for "file", then nothing happens. None of the ISchemeHandler ProcessRequestAsync methods are invoked.
I must be able to handle all requests, excluding *.html, in a separate handler
Essentially I just want to replicate the behavior of the MS Web-browser Control. There all I did was point to the entry page (index.htm), and everything loaded. Then if a user clicks any link, the control handled the action and started the correct process (content handler, i.e. Excel for Csv).
The code:
// Startup
var settings = new CefSettings();
settings.LogFile = #"c:\temp\ceflog.txt";
settings.LogSeverity = LogSeverity.Verbose;
settings.IgnoreCertificateErrors = true;
CefCustomScheme mailtoScheme = new CefCustomScheme();
mailtoScheme.SchemeName = "mailto";
mailtoScheme.SchemeHandlerFactory = new SchemeHandlerFactory();
CefCustomScheme filesScheme = new CefCustomScheme();
mailtoScheme.SchemeName = "file";
mailtoScheme.SchemeHandlerFactory = new SchemeHandlerFactory();
settings.RegisterScheme(mailtoScheme);
settings.RegisterScheme(filesScheme);
if (!Cef.Initialize(settings))
throw new InvalidOperationException("Failed to initialize the browser factory");
-- SchemeHandlerFactory
public class SchemeHandlerFactory : ISchemeHandlerFactory {
public ISchemeHandler Create() {
return new CustomSchemeHandler();
}
}
-- Handler
public class CustomSchemeHandler : ISchemeHandler {
private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public bool ProcessRequestAsync(IRequest request, ISchemeHandlerResponse response, OnRequestCompletedHandler requestCompletedCallback) {
_log.DebugFormat("Processing url: {0}", request.Dump());
var knownContentTypes = new[] {".csv", ".xsls", ".xlsx", ".pdf", ".txt"};
var ext=Path.GetExtension(request.Url);
if(knownContentTypes.Contains(ext)) {
_log.DebugFormat("Starting process for: {0}",request.Url);
Process.Start(request.Url);
return false;
}
return true;
}
The solution was to implement an IRequestHandler and use the OnBeforeResourceLoad event to check what content was requested. The ISchemeHandler is used for the "mailto" actions.
In my case I had to assign the request handler after the frame loaded. This allowed the web browser to render all content first.
Code sample GitHub example

DataContract doesn't work after publish into web site

I tried to solve by myself, but... Looks like I need help from people.
I have Business Silverlight application with WCF RIA and EntityFramework. Access to Database I get via LinqToEntites.
Common loading data from database I making by this:
return DbContext.Customers
This code returns full Customers table from DataBase. But sometimes I do not need to show all data. Easy way is use linq filters in client side by next code:
public LoadInfo()
{
...
var LO1 = PublicDomainContext.Load(PublicDomainContext.GetCustomersQuery());
LO1.Completed += LO1Completed;
...
}
private void LO1Completed(object sender, EventArgs eventArgs)
{
...
DatatViewGrid.ItemsSource = null;
DatatViewGrid.ItemsSource = loadOperation.Entities.Where(c=>c ...filtering...);
//or PublicDomainContext.Customers.Where(c=>c ...filtering...)
...
}
However this way has very and very important flaw: all data passing from server to client side via DomainService may be viewed by applications like Fiddler. So I need to come up with another way.
Task: filter recieving data in server side and return this data.
Way #1: LinqToEntites has a beautiful projection method:
//MSDN Example
var query =
contacts.SelectMany(
contact => orders.Where(order =>
(contact.ContactID == order.Contact.ContactID)
&& order.TotalDue < totalDue)
.Select(order => new
{
ContactID = contact.ContactID,
LastName = contact.LastName,
FirstName = contact.FirstName,
OrderID = order.SalesOrderID,
Total = order.TotalDue
}));
But, unfortunately, DomainServices cannot return undefined types, so this way won't work.
Way #2: I found next solution - make separate DTO classes (DataTransferObject). I just read some samples and made on the server side next class:
[DataContract]
public partial class CustomerDTO
{
[DataMember]
public int ISN { get; set; }
[DataMember]
public string FIO { get; set; }
[DataMember]
public string Listeners { get; set; }
}
And based this class I made a row of methods which return filtered data:
[OperationContract]
public List<CustomerDTO> Customers_Common()
{
return DbContext.Customers....Select(c => new CustomerDTO { ISN = c.ISN, FIO = c.FIO, Listeners = c.Listeners }).ToList();
}
And this works fine, all good...
But, there is strange problem: running application locally does not affect any troubles, but after publishing project on the Web Site, DomainService returns per each method HTTP 500 Error ("Not Found" exception). Of course, I cannot even LogIn into my application. DomainService is dead. If I delete last class and new methods from application and republish - all works fine, but without speacial filtering...
The Question: what I do wrong, why Service is dying with new classes, or tell me another way to solve my trouble. Please.
U P D A T E :
Hey, finally I solved this!
There is an answer: Dynamic query with WCF RIA Services
Your best shot is to find out what is causing the error. For that, override the OnError method on the DomainService like this:
protected override void OnError(DomainServiceErrorInfo errorInfo)
{
/* Log the error info to a file. Don't forget inner exceptions.
*/
base.OnError(errorInfo);
}
This is useful, because only two exceptions will be passed to the client, so if there are a lot of nested inner exceptions, you should still be able to see what actually causes the error.
In addition, you can inspect the error by attaching the debugger to the browser instance you are opening the site with. In VS2010 this is done by doing [Debug] -> [Attach to Process] in the menu-bar.

Inheritance security rules violated while overriding member in Silverlight

I am working on a web application in silverlight. I have overloaded the WebClient.GetWebRequest method as given below:-
public class WebClientWithCookies : WebClient
{
[SecurityCritical]
protected override WebRequest GetWebRequest(Uri address)
{
string cookieContent = HtmlPage.Document.Cookies;
WebRequest request = base.GetWebRequest(address);
HttpWebRequest webRequest = request as HttpWebRequest;
if (webRequest != null && cookieContent != null && cookieContent != string.Empty)
{
CookieContainer cookieContainer = new CookieContainer();
cookieContainer.Add(address, new Cookie() { Value = HtmlPage.Document.Cookies });
webRequest.CookieContainer = cookieContainer;
}
return request;
}
}
But I am getting the following exception:
System.TypeInitializationException was unhandled by user code
Message=The type initializer for 'SigmaWC.Utility.RestCommunicator'
threw an exception. TypeName=SigmaWC.Utility.RestCommunicator
StackTrace:
at SigmaWC.Utility.RestCommunicator..ctor()
at SigmaWC.App..ctor() InnerException: System.TypeLoadException
Message=Inheritance security rules violated while overriding member: 'SigmaWC.Utility.WebClientWithCookies..ctor()'. Security
accessibility of the overriding method must match the security
accessibility of the method being overriden.
StackTrace:
at SigmaWC.Utility.RestCommunicator..cctor()
InnerException:
Can anyone help in how to elevate the security settings in silverlight.
Documentation about this is scarce to say the least. However, there are a couple of resources which are useful:
MSDN Indicates that you cannot use framework members with a SecurityCriticalAttribute.
Types and members that have the SecurityCriticalAttribute cannot be used by Silverlight application code. Security-critical types and members can be used only by trusted code in the .NET Framework for Silverlight class library.
In the case of WebClient, the GetWebRequest method does not have this attribute, however the constructor does.
This MSDN Security blog Implies that if the default constructor has any Security attribute, the class cannot be used for inheritance in a Silverlight client.
Further to that, the aforementioned MSDN blog implies that Security attributes are ignored in Silverlight assemblies which are not part of the core framework. This may however only apply to Assembly level attributes.
Anyway, to cut a long story short. You cannot derive from WebClient because of the SecuritySafeAttribute on the constructor.
To illustrate the point, this also causes an exception at runtime:
public class MyWebClient : WebClient
{
}
The alternative is to roll your own WebClient. It takes a little work, but the following example does work with the following handler:
public class MyHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
foreach (Cookie cookie in context.Response.Cookies)
{
//Cookies from the client - there will be 1 in this case
}
}
...
public class MyWebClient
{
public MyWebClient()
{
}
public void InvokeWebRequest(Uri address)
{
//Set the cookie you want to use.
string cookieContent = "I like cookies";
// Register a http client - without this the following webRequest.CookieContainer setter will throw an exception
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
//This bit you know, but dont forget to set Name on your new Cookie.
HttpWebRequest webRequest = WebRequest.Create(address.AbsoluteUri) as HttpWebRequest;
if (webRequest != null && !String.IsNullOrWhiteSpace(cookieContent))
{
webRequest.CookieContainer = new CookieContainer();
webRequest.CookieContainer.Add(address, new Cookie() { Value = cookieContent, Name = "MyCookie" });
}
//Invoke the async GetResponse method.
webRequest.BeginGetResponse(o =>
{
HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(o);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
//Read the result
string result = reader.ReadToEnd();
}
foreach (Cookie cookie in response.Cookies)
{
//The cookies returned from the server.
}
}, null);
}
}

Silverlight Enabled WCF Service Exception Handling

I've got a Silverlight enabled WCF web service set up and I'm connecting to it from my Silverlight application.
The Service is not written using the ASync pattern but Silverlight generates the async methods automatically.
I have a method that within my service that has a chance of throwing an exception I can catch this exception but I'm not sure of the best way of handling this exception, I've noticed that the event args of the completed method contain an error property.
Is is possible to set the value of this error property?
Example Method
public class service
{
[OperationContract]
public Stream getData(string filename)
{
string filepath = HostingEnvironment.MapPath(filename);
FileInfo fi = new FileInfo(filenpath);
try
{
Stream s = fi.Open(FileMode.Open);
return s;
}
catch (IOException e)
{
return null;
}
}
}
Silverlight Code
btnFoo_Click(object sender, RoutedEventArgs e)
{
ServiceClient svc = new ServiceClient();
svc.getDataCompleted += new EventHandler<getDataCompletedEventArgs>(getData_Completed);
svc.getDataAsync("text.txt");
}
void getData_Completed(object sender, getDataCompletedEventArgs e)
{
e.Error //how can i set this value on the service?
}
Finally if the service is offline or times out is there anyway to catch this exception before it reaches the UnhandledException method within App.xaml?
Thanks
Since silverlight is using services asyncronously you dont get a synchronous exception throw, but instead it is stored in e.Error property, that you need to check in your ServiceCallCompleted method.
To answer your question
how can i set this value on the service?
Simply throw an exception on server and it can be enough given several other conditions.
You may want to introduce FaultContract on your WCF service method, and throw FaultException<T> which is a common way to deal with errors in WCF.
However fault result in return code 500 and silverlight won't be able to get response with such status code and have access to Fault object, even if you add that attribute to service.
This can be solved using several approaches.
Use the alternative client HTTP stack: You can register an alternative HTTP stack by using the RegisterPrefix method. See below for an outline of how to do this. Silverlight 4 provides the option of using a client HTTP stack which, unlike the default browser HTTP stack, allows you to process SOAP-compliant fault messages. However, a potential problem of switching to the alternative HTTP stack is that information stored by the browser (such as authentication cookies) will no longer be available to Silverlight, and thus certain scenarios involving secure services might stop working, or require additional code to work.
Modify the HTTP status code: You can modify your service to return SOAP faults with an HTTP status code of 200, Silverlight 4 so that faults will be processed successfully. How to do this is outlined below. Note that this will make the service non-compliant with the SOAP protocol, because SOAP requires a response code in the 400 or 500 range for faults. If the service is a WCF service, you can create an endpoint behavior that plugs in a message inspector that changes the status code to 200. Then you can create an endpoint specifically for Silverlight consumption, and apply the behavior there. Your other endpoints will still remain SOAP-compliant.
Faults in silverlight
Creating and Handling Faults in Silverlight
OR
[DataContract]
public class MyError
{
[DataMember]
public string Code { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public DateTime Time { get; set; }
}
public class service
{
[OperationContract]
public Stream getData(string filename, out MyError myError)
{
myError = null;
string filepath = HostingEnvironment.MapPath(filename);
FileInfo fi = new FileInfo(filenpath);
try
{
Stream s = fi.Open(FileMode.Open);
return s;
}
catch (IOException e)
{
myError = new MyError() { Code = "000", Message = ex.Message, Time = DateTime.Now };
return null;
}
}
}
I wish successful projects

Call a web service from a Windows Application

I am new to .NET and C#. I created a Web service, and I am able to view it from a Web page. When I try to call it from a Windows Application, I get the Exception 401 : unauthorized. Code compiles OK, but throws exception when running. This is the code from the Windows App. :
namespace BookStore
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Create a new instance of a service
localhost.Service1 datasvc = new localhost.Service1();
// Create instance of dataset, using WebService method GetTitleAuthors.
DataSet myData = datasvc.GetTitleAuthors();
// Set DataGrid's datasource to the myData DataSet.
dataGridView1.DataSource = myData;
//Expand all rows.
//dataGridView1.Expand(-1);
//Expand DataTable
//dataGridView1.NavigateTo(0, "Authors");
}
}
}
PS : I am using Windows Authentication in the website that hosts the web service.
I believe there is a property on the generated proxy to the effect of UseDefaultCredentials try setting that to true.
datasvc.UseDefaultCredentials = true;
Although it's been a while I think this will force the service to pass windows credentials.
I don't know what type your Service1 object inherits so I can't say what properties or methods you have associated with it, but whenever I know you can make calls to you web service with using
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(URL);
And then either using
req.UseDefaultCredentials = true;
or
req.Credentials = new NetworkCredential(userName, password);

Resources