asp.net mvc 2 render view to string, instead of partial - asp.net-mvc-2

I have this function:
public static string RenderViewToString(string controlName, object viewData) {
ViewDataDictionary vd = new ViewDataDictionary(viewData);
ViewPage vp = new ViewPage { ViewData = vd };
Control control = vp.LoadControl(controlName);
vp.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
And I call it like this:
string body = StringHelpers.RenderViewToString("~/Areas/Public/Views/Shared/RegistrationEmail.ascx", new RegistrationEmailViewModel { User = user });
And it returns a html-table with the user-info.
But I was wondering if there is a way to edit this to I can can return a View as string? so I can add masterpage, so it'll be easier to design all potential mails going out?
Thanks in advance
/M

Check out MVCContrib's email template system for sending emails.
http://codevanced.net/post/Sending-HTML-emails-with-ASPNET-MVC2-and-MVCContrib.aspx
Update:
This question and/or this article might help if you don't want to include Mvccontrib. Although I use Mvccontrib every day, it's harmless.

Related

Entity Framework 6: is it possible to update specific object property without getting the whole object?

I have an object with several really large string properties. In addition, it has a simple timestamp property.
What I trying to achieve is to update only timestamp property without getting the whole huge object to the server.
Eventually, I would like to use EF and to do in the most performant way something equivalent to this:
update [...]
set [...] = [...]
where [...]
Using the following, you can update a single column:
var yourEntity = new YourEntity() { Id = id, DateProp = dateTime };
using (var db = new MyEfContextName())
{
db.YourEntities.Attach(yourEntity);
db.Entry(yourEntity).Property(x => x.DateProp).IsModified = true;
db.SaveChanges();
}
OK, I managed to handle this. The solution is the same as proposed by Seany84, with the only addition of disabling validation, in order to overcome issue with required fields. Basically, I had to add the following line just before 'SaveChanges():
db.Configuration.ValidateOnSaveEnabled = false;
So, the complete solution is:
var yourEntity = new YourEntity() { Id = id, DateProp = dateTime };
using (var db = new MyEfContextName())
{
db.YourEntities.Attach(yourEntity);
db.Entry(yourEntity).Property(x => x.DateProp).IsModified = true;
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
}

Testing With A Fake DbContext and Autofixture and Moq

SO follow this example
example and how make a fake DBContex For test my test using just this work fine
[Test]
public void CiudadIndex()
{
var ciudades = new FakeDbSet<Ciudad>
{
new Ciudad {CiudadId = 1, EmpresaId =1, Descripcion ="Santa Cruz", FechaProceso = DateTime.Now, MarcaBaja = null, UsuarioId = 1},
new Ciudad {CiudadId = 2, EmpresaId =1, Descripcion ="La Paz", FechaProceso = DateTime.Now, MarcaBaja = null, UsuarioId = 1},
new Ciudad {CiudadId = 3, EmpresaId =1, Descripcion ="Cochabamba", FechaProceso = DateTime.Now, MarcaBaja = null, UsuarioId = 1}
};
//// Create mock unit of work
var mockData = new Mock<IContext>();
mockData.Setup(m => m.Ciudades).Returns(ciudades);
// Setup controller
var homeController = new CiudadController(mockData.Object);
// Invoke
var viewResult = homeController.Index();
var ciudades_de_la_vista = (IEnumerable<Ciudad>)viewResult.Model;
// Assert..
}
Iam tryign now to use Autofixture-Moq
to create "ciudades" but I cant. I try this
var fixture = new Fixture();
var ciudades = fixture.Build<FakeDbSet<Ciudad>>().CreateMany<FakeDbSet<Ciudad>>();
var mockData = new Mock<IContext>();
mockData.Setup(m => m.Ciudades).Returns(ciudades);
I get this error
Cant convert System.Collections.Generic.IEnumerable(FakeDbSet(Ciudad)) to System.Data.Entity.IDbSet(Ciudad)
cant put "<>" so I replace with "()" in the error message
Implementation of IContext and FakeDbSet
public interface IContext
{
IDbSet<Ciudad> Ciudades { get; }
}
public class FakeDbSet<T> : IDbSet<T> where T : class
how can make this to work?
A minor point... In stuff like:
var ciudades_fixture = fixture.Build<Ciudad>().CreateMany<Ciudad>();
The second type arg is unnecessary and should be:
var ciudades_fixture = fixture.Build<Ciudad>().CreateMany();
I really understand why you need a FakeDbSet and the article is a bit TL;DR... In general, I try to avoid faking and mucking with ORM bits and instead dealing with interfaces returning POCOs to the max degree possible.
That aside... The reason the normal syntax for initialising the list works is that there is an Add (and IEnumerable) in DBFixture. AutoFixture doesn't have a story for that pattern directly (after all it is compiler syntactic sugar and not particularly amenable to reflection or in line with any other conventions) but you can use AddManyTo as long as there is an ICollection in play. Luckily, within the impl of FakeDbSet as in the article, the following gives us an in:-
public ObservableCollection<T> Local
{
get { return _data; }
}
As ObservableCollection<T> derives from ICollection<T>, you should be able to:
var ciudades = new FakeDbSet<Cuidad>();
fixture.AddManyTo(ciudades.Local);
var mockData = new Mock<IContext>();
mockData.Setup(m => m.Ciudades).Returns(ciudades);
It's possible to wire up a customization to make this prettier, but at least you have a way to manage it. The other option is to have something implement ICollection (or add a prop with a setter taking IEnumerable<T> and have AF generate the parent object, causing said collection to be filled in.
Long superseded side note: In your initial question, you effectively have:
fixture.Build<FakeDbSet<Ciudad>>().CreateMany()
The problem becomes clearer then - you are asking AF to generate Many FakeDbSet<Ciudad>s, which is not what you want.
I haven't used AutoFixture in a while, but shouldn't it be:
var ciudades = new FakeDbSet<Ciudad>();
fixture.AddManyTo(ciudades);
for the moment I end doing this, I will keep reading about how use automoq, cause I'm new in this
var fixture = new Fixture();
var ciudades_fixture = fixture.Build<Ciudad>().CreateMany<Ciudad>();
var ciudades = new FakeDbSet<Ciudad>();
foreach (var item in ciudades_fixture)
{
ciudades.Add(item);
}
var mockData = new Mock<IContext>();
fixture.Create<Mock<IContext>>();
mockData.Setup(r => r.Ciudades).Returns(ciudades);

DataSet does not support System.Nullable<>

i have an app which has btn to preview report made in crystal report. I added Dataset as datasource of the report and dragged datatable from the toolbox and added the fields I need as columns. I got the instruction from this link http://aspalliance.com/2049_Use_LINQ_to_Retrieve_Data_for_Your_Crystal_Reports.2. This is my 2nd report the first one works and did not encounter any prob at all that is why i am confused, not to mention it also has nullable column. the error says: DataSet does not support System.Nullable<>.
private void ShowReportView()
{
string reportFile = "JudgeInfoFMReport.rpt";
ObservableCollection<tblJudgeFileMaint> judgeFileMaintList;
judgeFileMaintList = GenerateReport();
if (judgeFileMaintList.Count > 0)
{
CrystalReportViewerUC crview2 = new CrystalReportViewerUC();
crview2.SetReportPathFile(reportFile, judgeFileMaintList);
crview2.ShowDialog();
}
else
{
System.Windows.MessageBox.Show("No record found.", module, MessageBoxButton.OK, MessageBoxImage.Information);
}
}
private ObservableCollection<tblJudgeFileMaint> GenerateReport()
{
var result = FileMaintenanceBusiness.Instance.GetAllJudgeInfoList();
return new ObservableCollection<tblJudgeFileMaint>(result);
}
The error is in the part where I set datasource report.SetDataSource
public bool SetReportPathFile(string reportPathFile, IEnumerable enumerable)
{
string reportFolder = #"\CrystalReportViewer\Reports\";
string filename = System.Windows.Forms.Application.StartupPath + reportFolder + reportPathFile; // "\\Reports\\CrystalReports\\DateWiseEmployeeInfoReport.rpt";
ReportPathFile = filename;
report.Load(ReportPathFile);
report.SetDataSource(enumerable);
report.SetDatabaseLogon("sa", "admin007");
bRet = true;
}
_IsLoaded = bRet;
return bRet;
}
I read some answers and says I should set the null value to DBNUll which I did in the properties window of each column if it is nullable. Can anyone help me please? thanks
Your question can be seen in this post, but in a generic way ... that way you can pass an Object to a DataSet typed!
.NET - Convert Generic Collection to DataTable
figured it out. by using a collectionextention, copied somewhere, I forgot the link. Os to whoever it is who made the class, credits to you.
class method looks like this.
public statis class CollectionExtension {
public static DataSet ToDataSet<T>(this IEnumerable<T> collection, string dataTableName)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
if (string.IsNullOrEmpty(dataTableName))
{
throw new ArgumentNullException("dataTableName");
}
DataSet data = new DataSet("NewDataSet");
data.Tables.Add(FillDataTable(dataTableName, collection));
return data;
}
}
then you can use it by doing this in getting your source to your report:
private DataSet GenerateNeutralContEducReport(string dsName)
{
var contEduHistoryList = FileMaintenanceBusiness.Instance.GetManyNeutralFMContEducHistoryInfobyKeyword(CurrentNeutralFM.NeutralID, "NeutralID").ToList();
return CollectionExtensions.ToDataSet<tblContinuingEducationHistory>(contEduHistoryList, dsName);
}
I found little help from the other proposed answers but this solution worked.
A different way to solve this problem is to make the data column nullable.
DataColumn column = new DataColumn("column", Type.GetType("System.Int32"));
column.AllowDBNull = true;
dataTable.Columns.Add(column);
https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.allowdbnull?view=netcore-3.1
foreach (PropertyDescriptor property in properties)
{
dt.Columns.Add(property.Name, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType);
}

Using DynamicActivityProperty as OutArgument in ActivityBuilder

Greetings,
I'm trying to create a workflow using a ActivityBuilder, and then get the XAML.
This flow use a custom activity (WaitForInput) to handle bookmarks. This class inherits from NativeActivity.
I'm having a hard time finding a way to set 'Result' property of my WaitForInput activity, which expects a OutArgument.
Creating this same workflow by the VS designer, I could associate the boolean property 'MyResult' InOutArgument called 'wrapper'. Like this : [Wrapper.MyResult]
I would do this by code, and according to my research, I have to use DynamicActivityProperty.
The problem is that I don't know how to use my DynamicActivityProperty as OutArgument in this case.
This is an simplified version of the code:
var wrapper = new DynamicActivityProperty
{
Name = "Wrapper",
Type = typeof(InOutArgument<CommunicationWrapper>),
};
var activityBuilder = new ActivityBuilder();
activityBuilder.Properties.Add(wrapper);
var step1 = new FlowStep
{
//here's my problem
Action = new WaitForInput<bool> { BookmarkName = "step1", Result = ??? }
};
var flow = new Flowchart
{
StartNode = step1,
Nodes = { step1 }
};
I have founded a solution to my own problem
Result = new OutArgument<bool>(new VisualBasicReference<bool>
{ ExpressionText = "Wrapper.MyResult" }); }

Changing schema name on runtime - Entity Framework

I need to change the storage schema of the entities on runtime.
I've followed a wonderful post, available here:
http://blogs.microsoft.co.il/blogs/idof/archive/2008/08/22/change-entity-framework-storage-db-schema-in-runtime.aspx?CommentPosted=true#commentmessage
This works perfectly, but only for queries, not for modifications.
Any idea why?
Well, I was looking for this piece of code all around the Internet. In the end I had to do it myself. It's based on Brandon Haynes adapter, but this function is all you need to change the schema on runtime - and you don't need to replace the autogenerated context constructors.
public static EntityConnection Create(
string schema, string connString, string model)
{
XmlReader[] conceptualReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".csdl")
)
};
XmlReader[] mappingReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".msl")
)
};
var storageReader = XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".ssdl")
);
XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/02/edm/ssdl";
var storageXml = XElement.Load(storageReader);
foreach (var entitySet in storageXml.Descendants(storageNS + "EntitySet"))
{
var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
if (schemaAttribute != null)
{
schemaAttribute.SetValue(schema);
}
}
storageXml.CreateReader();
StoreItemCollection storageCollection =
new StoreItemCollection(
new XmlReader[] { storageXml.CreateReader() }
);
EdmItemCollection conceptualCollection = new EdmItemCollection(conceptualReader);
StorageMappingItemCollection mappingCollection =
new StorageMappingItemCollection(
conceptualCollection, storageCollection, mappingReader
);
var workspace = new MetadataWorkspace();
workspace.RegisterItemCollection(conceptualCollection);
workspace.RegisterItemCollection(storageCollection);
workspace.RegisterItemCollection(mappingCollection);
var connectionData = new EntityConnectionStringBuilder(connString);
var connection = DbProviderFactories
.GetFactory(connectionData.Provider)
.CreateConnection();
connection.ConnectionString = connectionData.ProviderConnectionString;
return new EntityConnection(workspace, connection);
}
The resulting EntityConnection should be passed as a parameter when instantiating the context. You can modify it, so all ssdl models are modified by this function, not only the specified one.
I've managed to resolve this issue by using a brilliant library, located in CodePlex (courtesy of Brandon Haynes), named "Entity Framework Runtime Model Adapter", available here:
http://efmodeladapter.codeplex.com/
I've tweaked it a bit, to fit our needs and without the need of replacing the designer code at all.
So, I'm good.
Thanks anyways, and especially to Brandon, amazing job!
I need import data from postgres database. It by default use schema "public". So I use Entity Framework CTP 4 "Code first". It by default use schema "dbo". To change it in runtime I use:
public class PublicSchemaContext : DbContext
{
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder builder)
{
builder.Entity<series_categories>().MapSingleType().ToTable("[public].[series_categories]");
}
public DbSet<series_categories> series_categories { get; set; }
}
It work for select, insert, update and delete data. So next test in pass:
[Test]
public void AccessToPublicSchema()
{
// Select
var db = new PublicSchemaContext();
var list = db.series_categories.ToList();
Assert.Greater(list.Count, 0);
Assert.IsNotNull(list.First().series_category);
// Delete
foreach (var item in db.series_categories.Where(c => c.series_category == "Test"))
db.series_categories.Remove(item);
db.SaveChanges();
// Insert
db.series_categories.Add(new series_categories { series_category = "Test", series_metacategory_id = 1 });
db.SaveChanges();
// Update
var test = db.series_categories.Single(c => c.series_category == "Test");
test.series_category = "Test2";
db.SaveChanges();
// Delete
foreach (var item in db.series_categories.Where(c => c.series_category == "Test2"))
db.series_categories.Remove(item);
db.SaveChanges();
}
Not an answer per se but a followup on Jan Matousek's Create[EntityConnection] method showing how to use from a DbContext. Note DB is the DbContext type passed to the generic repository.
public TxRepository(bool pUseTracking, string pServer, string pDatabase, string pSchema="dbo")
{
// make our own EF database connection string using server and database names
string lConnectionString = BuildEFConnectionString(pServer, pDatabase);
// do nothing special for dbo as that is the default
if (pSchema == "dbo")
{
// supply dbcontext with our connection string
mDbContext = Activator.CreateInstance(typeof(DB), lConnectionString) as DB;
}
else // change the schema in the edmx file before we use it!
{
// Create an EntityConnection and use that to create an ObjectContext,
// then that to create a DbContext with a different default schema from that specified for the edmx file.
// This allows us to have parallel tables in the database that we can make available using either schema or synonym renames.
var lEntityConnection = CreateEntityConnection(pSchema, lConnectionString, "TxData");
// create regular ObjectContext
ObjectContext lObjectContext = new ObjectContext(lEntityConnection);
// create a DbContext from an existing ObjectContext
mDbContext = Activator.CreateInstance(typeof(DB), lObjectContext, true) as DB;
}
// finish EF setup
SetupAndOpen(pUseTracking);
}
I was able to convert the solution from Jan Matousek to work in vb.net 2013 with entity framework 6. I will also try to explain how to use the code in vb.net.
We have a JD Edwards Database which uses different Schema's for each environment (TESTDTA, CRPDTA, PRODDTA). This makes switching between environments cumbersome as you have to manually modify the .edmx file if you want to change environments.
First step is to create a partial class that allows you to pass a value to the constructor of your entities, by default it uses the values from your config file.
Partial Public Class JDE_Entities
Public Sub New(ByVal myObjectContext As ObjectContext)
MyBase.New(myObjectContext, True)
End Sub
End Class
Next create the function that will modify your store schema .ssdl file in memory.
Public Function CreateObjectContext(ByVal schema As String, ByVal connString As String, ByVal model As String) As ObjectContext
Dim myEntityConnection As EntityConnection = Nothing
Try
Dim conceptualReader As XmlReader = XmlReader.Create(Me.GetType().Assembly.GetManifestResourceStream(model + ".csdl"))
Dim mappingReader As XmlReader = XmlReader.Create(Me.GetType().Assembly.GetManifestResourceStream(model + ".msl"))
Dim storageReader As XmlReader = XmlReader.Create(Me.GetType().Assembly.GetManifestResourceStream(model + ".ssdl"))
Dim storageNS As XNamespace = "http://schemas.microsoft.com/ado/2009/11/edm/ssdl"
Dim storageXml = XDocument.Load(storageReader)
Dim conceptualXml = XDocument.Load(conceptualReader)
Dim mappingXml = XDocument.Load(mappingReader)
For Each myItem As XElement In storageXml.Descendants(storageNS + "EntitySet")
Dim schemaAttribute = myItem.Attributes("Schema").FirstOrDefault
If schemaAttribute IsNot Nothing Then
schemaAttribute.SetValue(schema)
End If
Next
storageXml.Save("storage.ssdl")
conceptualXml.Save("storage.csdl")
mappingXml.Save("storage.msl")
Dim storageCollection As StoreItemCollection = New StoreItemCollection("storage.ssdl")
Dim conceptualCollection As EdmItemCollection = New EdmItemCollection("storage.csdl")
Dim mappingCollection As StorageMappingItemCollection = New StorageMappingItemCollection(conceptualCollection, storageCollection, "storage.msl")
Dim workspace = New MetadataWorkspace()
workspace.RegisterItemCollection(conceptualCollection)
workspace.RegisterItemCollection(storageCollection)
workspace.RegisterItemCollection(mappingCollection)
Dim connectionData = New EntityConnectionStringBuilder(connString)
Dim connection = DbProviderFactories.GetFactory(connectionData.Provider).CreateConnection()
connection.ConnectionString = connectionData.ProviderConnectionString
myEntityConnection = New EntityConnection(workspace, connection)
Return New ObjectContext(myEntityConnection)
Catch ex As Exception
End Try
End Function
Make sure that the storageNS namespace hardcoded value matches the one used in your code, you can view this by debugging the code and examining the storageXML variable to see what was actually used.
Now you can pass a new schema name, and different database connection info at runtime when you create your entities. No more manual .edmx changes required.
Using Context As New JDE_Entities(CreateObjectContext("NewSchemaNameHere", ConnectionString_EntityFramework("ServerName", "DatabaseName", "UserName", "Password"), "JDE_Model"))
Dim myWO = From a In Context.F4801 Where a.WADOCO = 400100
If myWO IsNot Nothing Then
For Each r In myWO
Me.Label1.Text = r.WADL01
Next
End If
End Using
These were the .net libraries used:
Imports System.Data.Entity.Core.EntityClient
Imports System.Xml
Imports System.Data.Common
Imports System.Data.Entity.Core.Metadata.Edm
Imports System.Reflection
Imports System.Data.Entity.Core.Mapping
Imports System.Data.Entity.Core.Objects
Imports System.Data.Linq
Imports System.Xml.Linq
Hope that helps anyone out there with the same issues.
I had a lot of problems getting this to work when using EF6 with an OData Data Service, so I had to find an alternate solution. In my case, I didn't really need to do it on the fly. I could get away with changing the schema when deploying to some test environments, and in the installer.
Use Mono.Cecil to rewrite the embedded .ssdl resources straight in the DLLs. This works just fine in my case.
Here is a simplified example of how you can do this:
var filename = "/path/to/some.dll"
var replacement = "Schema=\"new_schema\"";
var module = ModuleDefinition.ReadModule(filename);
var ssdlResources = module.Resources.Where(x => x.Name.EndsWith(".ssdl"));
foreach (var resource in ssdlResources)
{
var item = (EmbeddedResource)resource;
string rewritten;
using (var reader = new StreamReader(item.GetResourceStream()))
{
var text = reader.ReadToEnd();
rewritten = Regex.Replace(text, "Schema=\"old_schema\"", replacement);
}
var bytes = Encoding.UTF8.GetBytes(rewritten);
var newResource = new EmbeddedResource(item.Name, item.Attributes, bytes);
module.Resources.Remove(item);
module.Resources.Add(newResource);
}