solrnet with StructureMap - structuremap

I have a question about solrnet, and more specifically about mapping fields to C# objects.
I have the following code:
var mgr = new MappingManager();
mgr.Add(typeof(Article).GetProperty("Title"), "newsTitle");
SolrServerElement news = new SolrServerElement();
news.Id = "news";
news.DocumentType = typeof(Article).AssemblyQualifiedName;
news.Url = "http://127.0.0.1:8080/solrNews/news";
SolrServers servers = new SolrServers();
servers.Add(news);
ObjectFactory.Initialize(
x =>
{
x.AddRegistry(
new SolrNetRegistry(servers)
);
x.For<IReadOnlyMappingManager>().Use(mgr);
}
);
_solr = ObjectFactory.GetInstance<ISolrOperations<Article>>();
_solr.Ping();
It does not appear to map the solr fields to the object properties in C#. Any ideas?

IIRC StructureMap has a convention of "last registration wins", i.e. it becomes the default for the service. So if you register your IReadOnlyMappingManager after adding the SolrNetRegistry it should become the default.

In order to get the MappingManager working correctly you need to eject IReadOnlyMappingManager from ObjectFactory first of all, and then configure it to use your own MappingManager.
So it would be something like this:
var mgr = new MappingManager();
mgr.Add(typeof(Article).GetProperty("Title"), "newsTitle");
ObjectFactory.EjectAllInstancesOf<IReadOnlyMappingManager>();
ObjectFactory.Configure(x => x.For<IReadOnlyMappingManager>().Use(mgr));

Related

ASP.NET MVC + Dynamics NAV odata web services - how do I access related models?

I'm building an asp.net mvc application using Dynamics NAV Odata web services. Evertyhing is working fine and I created a controller for Service Orders using Linq queries. Then I got to the next step: accessing related models, and I'm stuck.
Lets take an example using page 5900 - Service Order and page 5903 - Service Item Lines:
Getting Service Orders or any other single model works great:
var query = from c in nav.ServiceOrder
select c;
But accessing related data fails:
var query = nav.ServiceOrder
.Expand(x => x.ServiceOrderServItemLines)
.Where(x => x.No == "SO000008");
I can access ServiceOrderServItemLines with the following url:
/DynamicsNAV71/OData/Company('the company')/ServiceOrder(Document_Type='Order',No='SO000008')/ServiceOrderServItemLines
But using expand does not seem to work.
Im not sure what the problem is. Are there no relations between the models?
If so, is there a way for me to add my own models with relations, and connect them to the odata service?
Or is it just a matter of expand not being supported in the service?
Any input would be much appreciated.
It seems that your serviceOrder has two keys. one is the Document_Type and one is the No. So please try
var query = nav.ServiceOrder
.Expand(x => x.ServiceOrderServItemLines)
.Where(x => x.Document_Type == "Order" && x.No == "SO000008");
If it doesn't solve your problem, Could you please provide the url sent by the expand query?
So after beating my head against this for some time I think I have an answer. I'll post my findings here, and hopefully it will save someone some trouble in the future.
Dynamics NAV (2013 R2) have relationships between header and list items as described here:
http://blogs.msdn.com/b/freddyk/archive/2009/05/28/handling-sales-orders-from-page-based-web-services-in-nav-2009sp1-and-rtm.aspx
In my case I want to create and access Service Item Lines for a Service Order.
Using SOAP to create Service Orders (Service Header table) and Service Item Lines can be done like this:
static void Main(string[] args)
{
ServiceOrder_Binding ctx = new ServiceOrder_Binding();
ctx.UseDefaultCredentials = true;
//Create a new Service Order
ServiceOrder so = NewSo(ctx);
//Add a couple of Service Item Lines to the Service Order
for (int i = 0; i < 5; i++)
NewSil(ctx, so.No);
}
private static ServiceOrder NewSo(ServiceOrder_Binding ctx)
{
ServiceOrder so = new ServiceOrder();
so.Customer_No = "50000";
so.Description = "New Service Order";
ctx.Create(ref so);
return so;
}
private static void NewSil(ServiceOrder_Binding ctx, string documentNo)
{
ServiceOrder so = ctx.Read(documentNo);
List<Service_Order_Line> SilList = so.ServItemLines.ToList();
Service_Order_Line Sil = new Service_Order_Line();
Sil.ServiceItemNo = "20";
Sil.Description = "New Service Item Line";
SilList.Add(Sil);
so.ServItemLines = SilList.ToArray();
ctx.Update(ref so);
}
Using Odata to read Service Orders (Service Header table) and Service Item Lines can be done like this:
static void Main(string[] args)
{
NAV ctx = new NAV(new Uri("http://localhost:7048/DynamicsNAV71/OData/Company('CRONUS Sverige AB')"));
ctx.UseDefaultCredentials = true;
//Eager loading - DOES NOT WORK!
var so = from s in ctx.ServiceOrder.Expand("ServiceOrderServItemLines")
where s.No == "SO000016"
select s;
//Lazy loading - WORKS!
var so2 = from s in ctx.ServiceOrder
where s.No == "SO000016"
select s;
ctx.LoadProperty(so2.First(), "ServiceOrderServItemLines");
}
Notice that lazy loading works, but eager loading doesn't.
For other related data, like Service Items for Service Item Lines, there doesn't seem to be any relationships. I will return with an update if I find something else, but what I ended up doing for now is passing related items in the ViewBag like this:
In the Controller Action:
var service_items = from s in ctx.ServiceItemList
where s.Customer_No.Equals(customerNo)
select s;
var serviceItemList = service_items.ToList();
ViewBag.serviceItemList = new SelectList(serviceItemList, "No", "Description");
In the View:
#Html.DropDownListFor(model => model.Service_Item_No, (IEnumerable<SelectListItem>)ViewBag.serviceItemList)
Hope this helps someone who like me is new to working with Dynamics NAV and Web Services :).

How to operate on the table many to many EF

I am working with ASP.NET MVC and I am using Entity Framework. While generating my database which has been created by DataBase First I got this relation which is shown below. My question is: how can I assign a role for a particular patient?
This slightly depends on how your project is structured, and any design patterns you're using, but the below code should point you in the right direction.
// query the DB for existing patient/role
var dbContext = new MyDbContext()
var patient = dbContext.Set<Patient>().FirstOrDefault(x => x.PatientID = patientId);
var role = dbContext.Set<Role>().FirstOrDefault(x => x.RoleID = roleId);
patient.Roles.Add(role);
dbContext.SaveChanges();
EDIT
Or something like this for a new instance of a patient...
var newPatient = new Patient {
Name = "NameHere"
....
};
newPatient.Roles.Add(role);
dbContext.Entry(newPatient).State = System.Data.EntityState.Added;
dbContext.SaveChanges();

ASP.NET MVC Unit Testing - Sessions

Having searched StackOverflow, and Google I think what I'm doing is suppose to be right, however results don't seem to be going well
[TestMethod]
public void LoginAction_Should_Return_View_and_User_Authenticated()
{
// Arrange
var mock = new Mock<ControllerContext>();
var mockSession = new Mock<HttpSessionStateBase>();
mock.Setup(p => p.HttpContext.Session).Returns(mockSession.Object);
var testData = FakeUserData.CreateTestUsers();
var repository = new FakeUserRepository(testData);
var controller = new AccountController(repository);
controller.ControllerContext = mock.Object;
// Act
var result = controller.Login("testuser1", "testuser1");
// Assert
Assert.AreEqual("testuser1", controller.HttpContext.Session["Username"]);
Assert.IsTrue((bool)controller.HttpContext.Session["IsAuthenticated"]);
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
}
When I run the test the value of controller.HttpContext.Session["Username"] is null, however I set the value to the username using a Session helper. Am I doing something completely wrong, or something else? Any help would be greatly appreciated.
Use Mock.Verify to check if underlying code tried to set Session["Username"].
If your code needs to set session variable and use it - take a look here.
Quickstart is priceless too.

Autofac with Open Generics and Type Specified at Runtime

The documentation states that Autofac supports open generics and I am able to register and resolve in a basic case like so:
Registration:
builder.RegisterGeneric(typeof(PassThroughFlattener<>))
.As(typeof(IFlattener<>))
.ContainerScoped();
Resolve:
var flattener = _container.Resolve<IFlattener<Address>>();
The above code works just fine. However, assuming that I will not know the type provided to IFlattener until runtime, I want to do something like this:
object input = new Address();
var flattener = (IFlattener)_container.Resolve(typeof(IFlattener<>), new TypedParameter(typeof(IFlattener<>), input.GetType()));
Is this possible with AutoFac? I got the idea from the following using StructureMap:
http://structuremap.sourceforge.net/Generics.htm
I'm trying to achieve the same goal outlined in this article.
This is certainly possible with Autofac. At "register time", this is what you basically do:
Register the open generic type (PassThroughFlattener<>)
Register any specific types (AddressFlattener)
Register a method that can be used to resolve an IFlattener based on a input object
At "resolve time", you will do:
Resolve the method
Call the method with input parameter(s) to resolve the IFlattener implementation
Here's a (hopefully) working sample:
var openType = typeof(IFlattener<>);
var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(PassThroughFlattener<>)).As(openType);
builder.Register<AddressFlattener>().As<IFlattener<Address>>();
builder.Register<Func<object, IFlattener>>(context => theObject =>
{
var closedType =
openType.MakeGenericType(theObject.GetType());
return (IFlattener) context.Resolve(closedType,
new PositionalParameter(0, theObject));
});
var c = builder.Build();
var factory = c.Resolve<Func<object, IFlattener>>();
var address = new Address();
var addressService = factory(address);
Assert.That(addressService, Is.InstanceOfType(typeof(AddressFlattener)));
var anything = "any other data";
var anyService = factory(anything);
Assert.That(anyService, Is.InstanceOfType(typeof(PassThroughFlattener<string>)));
If you don't know type until runtime you can build it using MakeGenericType:
var addressFlattener = _container.Resolve(typeof(IFlattener<>).MakeGenericType(typeof(Address)));

Linq to SQL update not working using Repository pattern

I am using asp.net mvc for an application. I've taken some guidance from Rob Conery's series on the MVC storefront. I am using a very similar data access pattern to the one that he used in the storefront.
However, I have added a small difference to the pattern. Each class I have created in my model has a property called IsNew. The intention on this is to allow me to specify whether I should be inserting or updating in the database.
Here's some code:
In my controller:
OrderService orderService = new OrderService();
Order dbOrder = orderService.GetOrder(ID);
if (ModelState.IsValid)
{
dbOrder.SomeField1 = "Whatever1";
dbOrder.SomeField2 = "Whatever2";
dbOrder.DateModified = DateTime.Now;
dbOrder.IsNew = false;
orderService.SaveOrder(dbOrder);
}
And then in the SQLOrderRepository:
public void SaveOrder(Order order)
{
ORDER dbOrder = new ORDER();
dbOrder.O_ID = order.ID;
dbOrder.O_SomeField1 = order.SomeField1;
dbOrder.O_SomeField2 = order.SomeField2;
dbOrder.O_DateCreated = order.DateCreated;
dbOrder.O_DateModified = order.DateModified;
if (order.IsNew)
db.ORDERs.InsertOnSubmit(dbOrder);
db.SubmitChanges();
}
If I change the controller code so that the dbOrder.IsNew = true; then the code works, and the values are inserted correctly.
However, if I set the dbOrder.IsNew = false; then nothing happens...there are no errors - it just doesn't update the order.
I am using DebuggerWriter here: http://www.u2u.info/Blogs/Kris/Lists/Posts/Post.aspx?ID=11 to trace the SQL that is being generated, and as expected, when the IsNew value is true, the Insert SQL is generated and executed properly. However, when IsNew is set to false, there appears to be no SQL generated, so nothing is executed.
I've verified that the issue here (LINQ not updating on .SubmitChanges()) is not the problem.
Any help is appreciated.
In your SaveOrder method you are always creating a new ORDER object. You need to change this so that if order.IsNew is false, it retrieves the existing one from the DB and updates it instead.
public void SaveOrder(Order order)
{
ORDER dbOrder;
if (order.IsNew)
{
dbOrder = new ORDER();
dbOrder.O_ID = order.ID;
}
else
{
dbOrder = (from o in db.ORDERS where o.O_ID == order.ID select o).Single();
}
dbOrder.O_SomeField1 = order.SomeField1;
dbOrder.O_SomeField2 = order.SomeField2;
dbOrder.O_DateCreated = order.DateCreated;
dbOrder.O_DateModified = order.DateModified;
if (order.IsNew)
db.ORDERs.InsertOnSubmit(dbOrder);
db.SubmitChanges();
}
I think you have the problem that your entity is detached from your context.
You should try to attach your entity back to your context if you want to update. The downside of LINQtoSQL is that for the re-attachment you'll need the original state of the object when it was detached...
Another solution is to re-get your entity from the context and copy all the data from your entity in the parameter. This will do until you'll have more complex entities.
What tvanfosson said.
I would just like to add that I use logic where if Id equals default(0 or Empty if using guids), then I assume it is new. Otherwise if I have the id passed in, then I go get the existing object and update it.

Resources