I'm not entirely sure how to explain this, but basically I am trying to use a Silverlight application hosted within an ASP.NET MVC application. I have a basic controller on the MVC side that contains a method which accepts some string parameter and returns an ActionResult (for the purpose of this program, that result is some Json data).
My problem arises when I handle the WebClient.OpenReadCompleted event within the Silverlight control. When the WebClient.OpenReadAsync method is called within this control, it successfully reaches the controller and then reports back to the relevant event handler as expected. However, when it is handled, the event arguments contain an error stating: "The remote server returned an error: NotFound.".
Previously, I have noticed this is caused when some part of my communication URL is incorrect - in this case it is not. From some Googling, I have also noticed that this is a generic error. As such, I'm rather stumped. To make matters more confusing, I use this exact same communication attempt in another part of the program, that retrieves an array of strings, and that works perfectly fine.
Please see the example code below (due to the nature of this program, I am unable to post the full code).
Silverlight Control
WebClient mClient = new WebClient();
public void RequestData()
{
mClient.OpenReadAsync(new Uri("http://localhost:51234/Home/GetData"));
mClient.OpenReadCompleted += new OpenReadCompletedEventHandler(mClient_OpenReadCompleted);
}
private void mClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if(!e.Cancelled && e.Error == null) // <-- e.Error here is a WebException
{
var serializer = new DataContractJsonSerializer(typeof(Data));
Data data = (Data)serializer.ReadObject(e.Result);
}
}
MVC Controller - named HomeController and accessed with "Home"
public ActionResult GetData()
{
return Json(new Data(), JsonRequestBehaviour.AllowGet);
}
Note
Here, Data contains three members of types; string, string and byte array. For the purpose of serialization, I have exposed all three members through public properties containing both get and set parts. I have also added a public constructor taking no arguments.
Any advice on this would be greatly appreciated.
Many thanks in advance.
UPDATE
I've just tried the same bit of code with different data, and it works fine. I wondered if it was the size of the data (as the first attempt was with very large data), but I don't understand why that would matter if the call managed to hit the controller.
If you want to see the real server-side exception, this may help you:
http://msdn.microsoft.com/en-us/library/ee844556(v=VS.95).aspx
Either approach described there would probably illuminate the real problem.
Related
I have a web API exposing ODATA from a SQL stored proc. I want to use a url like /odata/firmhierarchy(225) to pass 225 into a param for the stored proc. It just tells me that it can't find a matching resource. It hits the controller, just skips the method. Thoughts?
In webapiconfig
private static IEdmModel GenerateEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees");
builder.EntitySet<Employee>("FirmHierarchy");
return builder.GetEdmModel();
}
Context:
public virtual ObjectResult<Employee> sp_EmployeeHierarchy(Nullable<int> managerEmpID)
{
var managerEmpIDParameter = managerEmpID.HasValue ?
new SqlParameter("ManagerEmpID", managerEmpID) :
new SqlParameter("ManagerEmpID", 0);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<Employee>("sp_EmployeeHierarchy #ManagerEmpID", managerEmpIDParameter);
}
Only method in controller:
[Queryable]
public IQueryable<Employee> GetFirmHierarchy()
{
return db.sp_EmployeeHierarchy(225).AsQueryable();
//return SingleResult.Create(db.Employees.Where(employee => employee.EmpId == key));
}
This should work:
1.Write another method in your controller:
[EnableQuery]
public IQueryable<Employee> Get([FromODataUri] int key)
{
return db.sp_EmployeeHierarchy(key).AsQueryable();
}
Please note that [EnableQuery] is an attribute introduced in Web API for OData V4. If you are still using Web API for OData V1-3, use [Queryable] still.
2.Then you can send the request
GET /odata/firmhierarchy(225)
and get the employees.
I was able to make ODATA work for a table, when auto-generated from entity framework. However, that generation process didn't want to work for a complex type returned by a Table Valued Function (similar scenario to a SP), because it didn't seem to understand where the key was.
What I found was that I could however make it work. First, I check out this article. He sets things up a bit more manually, where his Get on a companyProcessingController ends up routing for id 3 as "http://localhost:10020/odata/companyProcessing(3)" .
This surprised me. My other generated classes set up the pattern that SomeEntity became SomeEntityController, with methods like GetSomeEntities, and a routing that seemed to me to match the method but dropping the word get. Therefore, dropping the entity name from the Get method name seemed different, but it worked. Proving that the path is actually matching the controller name, not the method name.
In this Case you configure the routing using the data type you're querying for, and the beginning of the controller name. Then the actual path utilizes the beginning of the controller name as well.
And then all of this just brings us essentially to the other posted solution, assuming your controller name is firmhierarchyController
So, now, making sense of this... Try going to http://localhost:55063/odata/$metadata , where your port may differ. You'll notice that ODATA exposes a DataType, which is accessed via a DataSet. When a client tries to query into ODATA, they are trying to query against the DataSet, getting items of the DataType.
The DataSet matching the controller name (less Controller), and the Get methods can indeed just be Get without further extension of the name - and otherwise in this scenario was giving me problems.
I have been looking for quite some time now on this problem.
Here's the deal.
I'm building a website that calls to a Web API to get its data. My Web API uses a library, working with repository pattern. My database model (EF Model-first) was build in the library. In that model I have a base class Pass. Then I have two derived classes, CustomerCard : Pass and Voucher : Pass. My model from EF Designer
I have a method to get all the CustomerCards.
public IQueryable<CustomerCard> GetAllPasses() {
IList<CustomerCard> allCards = new List<CustomerCard>();
var c_cards = context.Passes;
foreach (var c_card in c_cards) {
if (c_card is CustomerCard) {
allCards.Add((CustomerCard)c_card);
}
}
return allCards.AsQueryable<CustomerCard>();
}
In my ApiController, I use this method to get the passes and return them to the website, like this:
[HttpGet]
[Queryable]
public IQueryable<CustomerCard> GetAllPasses(string version) {
return passRepo.GetAllPasses().AsQueryable();
}
My Web API returns JSON format. This is my config to preserve referencing and stuff:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.Remove(config.Formatters.XmlFormatter);
I'm using IQueryable because I want to be able to page the data on my website. The api method is available at '/api/v1/passes/all'.
Here's the strange part. To test my paging, I call 1 pass per page.
For my first Pass, it works fine. But when I go to my second page, he also gets the correct pass, but the reference to User is gone.
As you can see in my model, the CustomerCard class has a property User. This indicates who owns the customer card.
So this call loads the user from the pass: 'api/v1/passes/all?$top=1'
but when I call to this one, the user instance is NULL: 'api/v1/passes/all?$top=1&$skip=1'.
However, when I call to 'api/v1/passes/all?$top=2', the User for the second pass IS loaded.
So this is where my mind get's blown! I don't get it? Why doesn't the user-reference comes along with the second one? Could it have something to do with the Lazy loading feature of the EF?
EDIT
When I use the extension method Include on context.passes, an error is thrown:
A specified Include path is not valid. The EntityType 'LCS_Model.Pass'
does not declare a navigation property with the name 'User'.
This is because Passes as a dbset, contains CustomerCard as well as Voucher. Is there a way I can tell my context to expect or convert it to a CustomerCard?
Can someone please help me. If you don't understand my question, ask away!
Thanks allready!
EDIT 2
The method on my API controller is now
[HttpGet]
[Queryable]
public IQueryable<CustomerCard> GetAllPasses(string version) {
return context.Passes.Include("User").OfType<CustomerCard>();
}
This gives me my correct items. I have 2 customer cards in my db. Both are from the same user. My API has the user still loaded. The moment my website receives the response, the User property becomes null. My guess is that it's because it is still referencing to the same user from the first element of the array. Is that possible? And if yes, how can I prevent that from happening?
Yes, you need to make sure any related records are included when you do your query. See this for some examples. Secondly... I fail to understand why you are doing all that work with the for loop... That's a lot of absolutely needless and wasted work for the server to do if you want to do any paging. I'm thinking, besides any other filters you might want to apply, your GetAllPasses should look something like this.
public IQueryable<CustomerCard> GetAllPasses() {
return context.Passes.Include(r => r.User);
}
Edit (2): I need to read better. I have to confess, I'm not familiar with type inheritance in EF. I found some things that might work here: table per hierarchy, table per concrete type, and see also also MSDN Queryable.OfType<TResult>. This is a guess, but let's try:
public IQueryable<CustomerCard> GetAllPasses() {
return context.Passes.OfType<CustomerCard>().Include(r => r.User);
}
I'm trying to return a JSON list of stuff from my server via an ASP.NET MVC front layer:
var stuff = repo.GetStuff();
return Json(stuff);
However, instead of the expected JSON, I get an error message stating
A circular reference was detected while serializing an object of type 'System.Reflection.RuntimeModule'.
I think I've found where this happens, but to explain it I need a simple example domain model as follows:
I am (lazily?) loading a selection of documents from NHibernate, like so:
var session = getNHibernateSession();
var query = new NhQueryable<Document>(session.GetSessionImplementation());
var docs = query.ToList().AsEnumerable();
I then pass the documents to return a JsonResult in my controller:
return Json(docs, JsonRequestBehavior.AllowGet);
Now, when Json() serailizes the collection, it walks over the properties of a document, finds a person. It serializes that person, and finds a project. It serializes the project, and finds - that's right - the person again! Since I'm lazy loading, it can just keep walking for ever if nothing stops it, but it's stopped by a circular reference error.
I don't really need to go all these levels down (I'd be fine without loading the project in the first place) - can I somehow affect how Json() serializes this collection, to not go further than, say, 2 levels down? I've googled around a little, but most of what I find seems to be from people who decided to use a serializing library directly, rather than just using the built-in functionality in .NET MVC. (Note: The solution to this problem must be possible to apply specifically to this case, since I might want to get JSON lists of people, including projects, somewhere else in the application...)
If you are retrieving Json, you have a service api. You have to design the api besides the implementation. Does the page that will be using it need all those fields and collections? probably not. What about adding more properties for other features and services? They will start appear in all the requests.
What you need is to use a ViewModel or just an anonymous type with the desired structure:
var session = getNHibernateSession();
var query = new NhQueryable<Document>(session.GetSessionImplementation());
var docs = query.ToList();
var result = query.Select(x => new {
x.Id,
x.Name,
People = new { p.Id,
p.Name,
p.Title
}
});
return Json( result, JsonRequestBehavior.AllowGet);
This way you can control what is being rendered and how.
It's already been answered here.
Also, it's generally a bad idea to expose your domain entities like this. If it's for read-only purposes it might not be so bad, but if any of your action methods accept a domain entity, then a specifically formatted request can overwrite properties on your domain entity that you don't want to (such as your PK).
To preserve object references in JSON, add the following code to Application_Start method in the Global.asax file:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;
Right now I'm having an issue with a Singleton that I just wrote for use in ASP.NET MVC -- My Singleton looks like this:
public sealed class RequestGenerator : IRequestGenerator
{
// Singleton pattern
private RequestGenerator()
{
requestList = new Stack<Request>();
appSettings = new WebAppSettings();
}
private static volatile RequestGenerator instance = new RequestGenerator();
private static Stack<Request> requestList = new Stack<Request>();
// abstraction layer for accessing web.config
private static IAppSettings appSettings = new WebAppSettings();
// used for "lock"-ing to prevent race conditions
private static object syncRoot = new object();
// public accessor for singleton
public static IRequestGenerator Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new RequestGenerator();
}
}
}
return instance;
}
}
private const string REQUESTID = "RequestID";
// Find functions
private Request FindRequest(string component, string requestId)
private List<Request> FindAllRequests(string component, string requestId)
#region Public Methods required by Interface
// Gets and increments last Request ID from Web.Config, creates new Request, and returns RequestID
public string GetID(string component, string userId)
// Changes state of Request to "submitted"
public void SetID(string component, string requestId)
// Changes state of Request to "success" or "failure" and records result for later output
public void CloseID(string component, string requestId, bool success, string result)
// Verifies that Component has generated a Request of this ID
public bool VerifyID(string component, string requestId)
// Verifies that Component has generated a Request of this ID and is owned by specified UserId
public bool VerifyID(string component, string userId, string requestId)
// Returns State of Request ID (Open, Submitted, etc.)
public Status GetState(string component, string requestId)
// Returns Result String of Success or Failure.
public string GetResult(string component, string requestId)
#endregion
}
And my controller code looks like this:
public ViewResult SomeAction()
{
private IRequestGenerator reqGen = RequestGenerator.Instance;
string requestId = reqGen.GetID(someComponentName, someUserId);
return View(requestId);
}
Everything works okay the first time I hit the controller. "reqGen" is assigned the instance of the Singleton. A new instance of Request is added to the internal list of the Singleton. And then we return a View(). The next time I hit this controller's SomeAction(), I'm expecting the Singleton to contain the List with the instance of SomeClass that I had just added, but instead the List is empty.
What's happened? Has Garbage Collection gobbled up my object? Is there something special I need to consider when implementing the Singleton pattern in ASP.NET MVC?
Thanks!
EDIT: Ahh, the lightbulb just went on. So each new page request takes place in a completely new process! Got it. (my background is in desktop application development, so this is a different paradigm for me...)
EDIT2: Sure, here's some more clarification. My application needed a request number system where something being requested needed a unique ID, but I had no DB available. But it had to be available to every user to log the state of each request. I also realized that it could double as a way to regulate the session, say, if a use double-clicked the request button. A singleton seemed like the way to go, but realizing that each request is in its own process basically eliminates the singleton. And I guess that also eliminates the static class, right?
EDIT3: ok, I've added the actual code that I'm working with (minus the implementation of each Method, for simplicity sake...) I hope this is clearer.
EDIT4: I'm awarding the green check mark to Chris as I'm beginning to realize that an application-level singleton is just like having a Global (and global's are evil, right?) -- All kidding aside, the best option really is to have a DB and SQLite seems like the best fit for now, although I can definitely see myself moving to an Oracle instance in the future. Unfortunately, the best option then would be to use an ORM, but that's another learning curve to climb. bugger.
EDIT5: Last edit, I swear. :-)
So I tried using HttpRuntime.Cache, but was surprised to find that my cache was getting flushed/invalidated constantly and couldn't figure out what was going on. Well, I was getting tripped up by a side-effect of something else I was doing: Writing to "Web.config"
The Answer --> Unbeknownst to me, when "web.config" is altered in anyway, the application is RESTARTED! Yup, everything gets thrown away. My singleton, my cache, everything. Gah. No wonder nothing was working right. Looks like writing back to web.config is generally bad practice which I shall now eschew.
Thanks again to everyone who helped me out with this quandary.
The singleton is specific to the processing instance. A new instance is being generated for each page request. Page requests are generally considered stateless so data from one doesn't just stick around for another.
In order to get this to work at the application level, the instance variable will have to be declared there. See this question for a hint on how to create an application level variable. Note that this would make it available across all requests.. which isn't always what you want.
Of course, if you are trying to implement some type of session state then you might just use session or use some type of caching procedure.
UPDATE
Based on your edits: A static class should not maintain data. It's purpose is to simply group some common methods together, but it shouldn't store data between method calls. A singleton is an altogether different thing in that it is a class that you only want one object to be created for the request.
Neither of those seem to be what you want.
Now, having an application level singleton would be available to the entire application, but that crosses requests and would have to be coded accordingly.
It almost sounds like you are trying to build an in memory data store. You could go down the path of utilizing one of the various caching mechanisms like .NET Page.Cache, MemCache, or Enterprise Library's Caching Application Block.
However, all of those have the problem of getting cleared in the event the worker process hosting the application gets recycled.. Which can happen at the worst times.. And will happen based on random things like memory usage, some timer expired, a certain number of page recompiles, etc.
Instead, I'd highly recommend using some type of persisted storage. Whether that be just xml files that you read/write from or embedding something like SQL Lite into the application. SQL Lite is a very lightweight database that doesn't require installation on the server; you just need the assemblies.
You can use Dependency Injection to control the life of the class. Here's the line you could add in your web.config if you were using Castle Windsor.
<component id="MySingleton" service="IMySingleton, MyInterfaceAssembly"
type="MySingleton, MyImplementationAssembly" lifestyle="Singleton" />
Of course, the topic of wiring up your application to use DI is beyond my answer, but either you're using it and this answer helps you or you can take a peak at the concept and fall in love with it. :)
I need to create something similar to how MVC invokes an Method(Action) and also uses the Model Binder to map a NamedValueCollection to the parameters on that method. Basically I have a Controller action that needs to dynamically call a method on a class, the controller has any information sent in a form or query string plus the name of the method to invoke as a string.
As far as I am concerned it's the same as invoking an action. I am essentially passing it down another level (there is a good reason I can't have these methods on the controller btw).
I downloaded the ASP.Net MVC 1.0 Source but there are a bunch of classes, I am having trouble finding the code that handles this.
I know how to invoke an method whose name is contained in a string, but maybe there is a better way that MVC uses. I also need to know how to use the Model Binders to make Request.Form + Query Strings to that methods parameters.
If anyone could point me to either the code in the MVC source that does this or point me in the right direction with regards to using the default Model Binder in MVC manually I would be grateful.
Let me know if I can make this clearer.
Thanks
It's complicated. FindAction is called on ControllerActionInvoker. This calls, eventually, ReflectedControllerDescriptor.FindAction, which in turn calls ActionMethodSelector.FindActionMethod, which calls RunSelectionFilters on the same type. That method takes a list of methods passed him by the collar, and iterates them, examining the arguments on each method and comparing them with the values in the request. Because this has to run quickly on a request comes in, this is all cached, and because it is designed to be extensible, there are some abstract types in between the layers I've described. Hence, it can be a little difficult to follow at first, and it would probably be difficult to repurpose it for non-controller logic. However, you could use it as a model for implementing your own system. I think it's a little too complicated for a domain-specific application. The number of extension points is probably appropriate for the MVC framework, but for your own code, YAGNI.
I hope this gives you enough to get started, however.
Regarding using a model binder without the web stack: Well, you still need MVC, but not necessarily a web server. Here's how we do it in a unit test:
internal static T Bind<T>(string prefix, FormCollection collection, ModelStateDictionary modelState) where T:BaseTimeRecordPresentationModel
{
var mbc = new ModelBindingContext()
{
ModelName = prefix,
ModelState = modelState,
ModelType = typeof(T),
ValueProvider = collection.ToValueProvider()
};
IModelBinder binder = new TimeRecordModelBinder();
var cc = new ControllerContext();
return binder.BindModel(cc, mbc) as T;
}
internal static T BindAndAssertValid<T>(string prefix, FormCollection collection) where T:BaseTimeRecordPresentationModel
{
var msd = new ModelStateDictionary();
var result = Bind<T>(prefix, collection, msd);
if (!msd.IsValid)
{
Assert.Fail(ModelStateValidationSummary(msd));
}
return result;
}